How to get the size of a Canvas Group (needed for a shader)

Godot Version

4.4 stable


Question

Hi there! I’m trying to make a shader that draws a texture as either a shadow on land or a reflected copy on water—but I only know how to do this on a Sprite2D. When I switch to a CanvasGroup, I lose access to the node’s size inside the shader, and I can’t figure out how to query it.

I know CanvasGroups render their children into an off-screen buffer, but I need the width×height of that buffer in pixels, so I can translate my UV into the right world-pixel position for sampling my terrain mask.

Below is my working Sprite2D shader (where I simply use textureSize(TEXTURE, 0) to get the sprite’s size). Any ideas how to get the CanvasGroup’s dynamic size either in GDScript or inside its shader?


shader_type canvas_item;

uniform sampler2D terrain_mask;
uniform vec2        map_size_pixels       = vec2(4096.0, 2304.0);

uniform vec2        mech_world_pos_pixels;
uniform bool        center_pos            = true;

uniform float       lower_water_threshold : hint_range(0.0, 1.0) = 0.0;
uniform float       upper_water_threshold : hint_range(0.0, 1.0) = 1.0;

void fragment() {
    vec4 base = COLOR;
    if (base.a < 0.01) {
        discard; // skip fully transparent pixels
    }

    // 2) figure out which pixel in terrain_mask we need
    //    mech_world_pos_pixels is the top-left corner of your shadow sprite in world-space
    vec2 texture_size = vec2(textureSize(TEXTURE, 0));
    vec2 world_pixel  = mech_world_pos_pixels + UV * texture_size;

    // center the position if we're asked to
    if (center_pos) {
        world_pixel -= texture_size * 0.5;
    }

    // 3) convert to [0,1] UVs for the 4096×2304 mask
    vec2 mask_uv = world_pixel / map_size_pixels;

    // 4) sample terrain_mask
    float t = texture(terrain_mask, mask_uv).r;

    bool is_water =
        (lower_water_threshold > 0.0 && t <= lower_water_threshold) ||
        (upper_water_threshold < 1.0 && t >= upper_water_threshold);

    // 5) pick shadow or reflection
    if (is_water) {
        // on water → reflection
        COLOR.a = base.a * 0.5;
    } else {
        // on land → shadow
        COLOR = vec4(0.0, 0.0, 0.0, base.a * 0.5);
    }
}

In case anyone’s wondering, I found a solution. The solution was to use SCREEN_UV coordinates. In CanvasGroup shaders you can use the SCREEN_UV coordinates to see where any pixel is on the screen and then you can use a large terrain masks SCREEN_UV coordinates in conjunction with the viewports offset and size in order to figure out where on the large mask you should check. So yeah, avoids the issue of needing the CanvasGroup size, though I will say it would be nice if that property of CanvasGroups was made accessible in a future version of Godot!