How to check color of adjacent pixels in fragment shader?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Diet Estus

I am playing around with shaders in my 2D project in Godot 3.

I am trying to write a fragment() method that samples my sprite’s texture, then checks whether the current pixel has any red neighbors (that is, whether there is a red pixel immediately above, below, left, or right). If the current pixel has any red neighbors, I want to change the current pixel to green.

Sampling my sprite’s texture and changing the current pixel to green are easy.

shader_type canvas_item;
render_mode unshaded;

void fragment()
{

    // sample texture to get color data
    vec4 tex_color = texture(TEXTURE, UV);

    // check if neighbors are red...

    // if there is a red neighbor...
    
    // change current pixel to green
    {
    COLOR = vec4(0.0, 1.0, 0.0, 1.0)
    }

}

But how would I go about checking the color of neighboring pixels?

:bust_in_silhouette: Reply From: SIsilicon

There is this built-in function called textureSize that can be useful in this situation.
You can get the size of the pixels with it.

vec2 pixel_size = 1.0 / vec2(textureSize(TEXTURE, 0));

With this pixel in hand, neighbour sampling is as easy as:

//pixel_off is just the amount of pixels your texture coord is offseted by.
vec4 tex = texture(TEXTURE, UV + pixel_off * pixel_size);

So your code should look something like:

shader_type canvas_item;
render_mode unshaded;

void fragment()
{

    vec2 pixel_size = 1.0 / vec2(textureSize(TEXTURE, 0));
    for(int y = -1; y <= 1; y++)
    for(int x = -1; x <= 1; x++)
    {
        vec2 pixel_off = vec2(float(x), float(y));
        vec4 tex = texture(TEXTURE, UV + pixel_off * pixel_size);
        if(tex.rgba == vec4(1.0, 0.0, 0.0, 1.0))
        {
            COLOR = vec4(0.0, 1.0, 0.0, 1.0);
            break;
        }
    }
}

Thanks, I will work on this more tomorrow. I wonder if the built-in TEXTURE_PIXEL_SIZE would give me the same value as your manual calculation usIng textureSize?

Diet Estus | 2018-05-06 06:23

I don’t there is such a function.

SIsilicon | 2018-05-06 16:50

There is a built-in for fragment shaders of type canvas_item:

in vec2 TEXTURE_PIXEL_SIZE Default 2D texture pixel size.

See docs.

So, to check adjacent pixels, you only need lines like this:

vec4 tex_color = texture(TEXTURE, UV);
vec4 right_neighbor_color = texture(TEXTURE, UV + vec2(TEXTURE_PIXEL_SIZE.x, 0));

You don’t need to do the manual calculation of pixel size.

Diet Estus | 2018-05-06 20:09

Guess we both learned something today.

SIsilicon | 2018-05-06 21:47