openglglslfragment-shader

Unexpected pixel selected in fragment shader


I have a simple shader drawing a rectangle in which I want to change color in the fragment shader depending on the fragment coordinate.

A basic implementation binding normalized UVs to vertices works, but I can't get a reliable render. Because whatever I do with the UVs, I can't select the right pixel and sometimes hits a neighbor.

To simplify, let's say I try to draw a sub rectangle playing with UVs like this :

enter image description here

  uniform vec2 size; // size of the sub rectangle in normalized space
  in vec2 uv;  

  void main() {
    vec2 mask_xy = step(uv, size);
    float mask = mask_xy.x * mask_xy.y;
    color = mix(vec4(1,0,0,1), vec4(0,0,1,1), mask);
}

If I ask a specific size let's say (9 * 9) pixels : sometimes I get the right render, and sometimes I get (10 * 9). And it seems to depend on multiple factors :

The thing is that I get different values on x & y axis despite drawing a square shape, asking for a square size, in a square window. This assymetry is really bugging me.

Notice that the geometry of the rectangle itself is always correct, there is nothing wrong happening with the vertices position.

I tried putting some epsilon value into the step function to avoid rounding errors but I couldn't find any meaningfull pattern.

I tried another approach using gl_FragCoord instead of UVs with an implementation like that :

  uniform vec2 size; // size of the sub rectangle in window space
  uniform vec4 box; // [xmin, xmax, ymin, ymax] in window space

  void main() {
    vec2 mask_xy = step(gl_FragCoord.xy - box.xz, size);
    float mask = mask_xy.x * mask_xy.y;
    color = mix(vec4(1,0,0,1), vec4(0,0,1,1), mask);
}

gl_FragCoord is supposed to be centered in the pixel, so step should always choose the right boundary. But even with this implementation, I get the same behavior.

I am running out of ideas to fix this.

Notice that I only tried with this specific renderer (not actually working with the GPU) :


Solution

  • OK, so I finally got it right with both gl_FragCoord and uv implementations.

    The main problem was lying in the vertices position (the one thing I took for granted ...)

    Notice that the geometry of the rectangle itself is always correct, there is nothing wrong happening with the vertices position.

    The solution was to declare the coordinates in window space and use a projection matrix including a normalization factor of window_size - 1 instead of window_size.

    This difference had no impact on the output coordinates but it messed up my uv computations with no distinguishable pattern.