How to use a shader generated shape as mask to clip children?

Godot Version

v4.4.1.stable.official [49a5bc7b6]

Question

I want to use the clip children function on CanvasItem, and I want to use a shader generated shape as mask, so I can achieve some dynamic effect.

The problem is: when I apply a shader to the Parent node(a ColorRect node), the clip children function doesn’t seem to work. All my children ColorRect nodes are not clipped.

So, what’s the proper way to use shader generated mask to cilp children?

Here is my setup:

Here is the shader on parent ColorRect:

shader_type canvas_item;

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

float random_float (in float x) {
    return fract(sin(x)*1e4);
}

float random_vec (in vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

float pattern(vec2 st, vec2 v, float t) {
    vec2 p = floor(st+v);
    return step(0.5, random_vec(100.+p*.000001)+random_float(p.x)*0.5 );
}

void fragment() {
 	vec2 st = UV * vec2(1.0, -1.0) + vec2(0.0, 1.0);
    vec2 grid = vec2(100.0,50.);
    st *= grid;
    vec2 ipos = floor(st);
    vec2 fpos = fract(st);
    vec2 vel = vec2(TIME*2.*max(grid.x,grid.y)); // time
    vel *= vec2(-1.,0.0) * random_float(1.0+ipos.y); // direction
	
    vec3 color = vec3(pattern(st,vel,0.5+u_mouse.x/u_resolution.x));
    color *= step(0.2,fpos.y);
    COLOR = vec4(color, color.r);
}

You could probably start with a basic minimal shader to get clipping working at all at first. It’s hard to tell what you have there going on and if any part of it is wrong.
As far as I can tell, clip children should just take the color from the screen but replace alpha taking it from your clipping node. It however involves reading the screen texture and is probably affected by a bunch other things in the engine. Look into screen reading shaders and if there are any related requirements.

It seems that the canvas item first creates the clip mask without applying a material and then draws itself using the material. Not sure if this should be considered a bug or a limitation but you’d probably open an issue in the issue tracker

As a workaround you could use a SubViewport with its SubViewport.transparent_bg property enabled and where you should render the ColorRect with the shader applied. Then change the root ColorRect to a TextureRect and set a ViewportTexture as its TextureRect.texture property pointing to the SubViewport

1 Like

Thanks a lot! That’s a great workaround even without adding any script.

Since a workaround simple as this exists, I don’t think this would worth to be discussed as an issue. And to fix this, it requires a change in the render pipeline, which usually cause many other issues.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.