Clipping outside texture shader

360 Views Asked by At

I'm trying to create a shader which decides the silhouette of the sprite by giving a texture (sampler2D) as input in shader parameter and clips anything outside it's bound

And so far this is what I've been able to come up with:

shader_type canvas_item;

uniform sampler2D clip_texture;

void fragment(){
    vec4 color = texture(clip_texture, UV);
    
    if(color.a==0.0)
        COLOR=vec4(0.0, 0.0, 0.0, 0.0);
    else
        COLOR=texture(TEXTURE, UV);
    
}

But this approach seems to squeeze the Clip Texture to the sprite resolution

enter image description here

I'm guessing UV being between 0.0 - 1.0 for both has something to do with this

So how do I fix this ?

Edit: further explanation on what I'm trying to achieve

Assume an image placed on top of another image (The image being placed on top will be passed as shader parameter)
enter image description here

Now if we crop only the overlapping part:
enter image description here

Now ofc we should also be able to move the location of the image placed on top (maybe pass x-y shader parameters?) and get the same effect:
enter image description here enter image description here

This is what I'm trying to achieve using shaders

1

There are 1 best solutions below

0
On BEST ANSWER

The problem was that the 0.0 - 1.0 is the UV from icon.png, so 1.0 maps the extents of the clip texture to 64x64, shrinking it.

shader_type canvas_item;

uniform sampler2D clip_texture;
uniform vec2 clip_texture_size;

void fragment(){
    vec2 texture_size = 1.0 / TEXTURE_PIXEL_SIZE;
    vec2 texture_ratio = texture_size / clip_texture_size;
    vec2 clip_UV = UV * texture_ratio;

    vec4 color = texture(clip_texture, clip_UV);
    
    if(color.a==0.0)
        COLOR=vec4(0.0, 0.0, 0.0, 0.0);
    else
        COLOR=texture(TEXTURE, UV);
    
}

For icon.png, TEXTURE_PIXEL_SIZE is equal to vec2(1.0/64.0, 1.0/64.0). The reciprocal of this is the texture size: 1.0 / TEXTURE_PIXEL_SIZE. If you divide the texture size by the clip texture size, this gives the ratio between the texture and the clip texture.

You can determine the size of a texture with textureSize() instead of using a uniform, but it is only available in GLES 3.

Here is a version with an offset uniform per your edit:

shader_type canvas_item;

uniform sampler2D clip_texture;
uniform vec2 clip_texture_size;
uniform vec2 clip_texture_offset;

void fragment(){
    vec2 texture_size = (1.0 / TEXTURE_PIXEL_SIZE);
    vec2 texture_ratio = texture_size / clip_texture_size;
    vec2 clip_UV = UV * texture_ratio + clip_texture_offset;
    
    vec4 color;
    if (clip_UV.x > 1.0 || clip_UV.x < 0.0 || clip_UV.y > 1.0 || clip_UV.y < 0.0) {
        color = vec4(0.0, 0.0, 0.0, 0.0)
    }
    else {
        color = texture(clip_texture, clip_UV);
    }
    
    if(color.a==0.0)
        COLOR=vec4(0.0, 0.0, 0.0, 0.0);
    else
        COLOR=texture(TEXTURE, UV);
    
}