Search code examples
glslwebglfragment-shader

Explicit uv.x value forms a horizontal line with length function


I am trying to get better with something as complex as glsl but it's taking some time to grasp certain concepts coming from a PHP/JS background.

In the following fragment shader code, I don't understand why are we getting a horizontal bar in the center?

The origin is shifted to the center, fine. And when I +=or -= the uv.x value, it's adding or subtracting the .x value for each pixel. That is also understood as doing this moves the resultant circle around.

But when you change this -= or += to just = it should mean that every pixel gets its .x value fixed to be .2(in this case) which should give a messed up graphic as every pixel is moving itself to the .2 spot on x-axis? Could someone please explain in layman terms? Thanks.

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;

void main(){
  vec2 uv = gl_FragCoord.xy/u_resolution.xy;
  uv.x *= u_resolution.x/u_resolution.y;

  // Remap the space to -1. to 1.
  uv = uv *2.-1.;

  // The following will move the circle around
  // uv.x += 0.2;
  // uv.x -= 0.2;

  // But why does this creates the horizontal bar?
  uv.x = .2;

  // Visualize the distance field
  gl_FragColor = vec4(vec3(step( .3, length(uv))),1.0);
}

Solution

  • Short answer:

    The result of length(vec2(0.2, uv.y)) is equal for all the pixels in one row.


    The fragment shader is executed (concurrently) for each fragment and the built-in fragment shader input variable gl_FragCoord.xy is different for each fragment. It ranges from (0, 0) for the bottom left fragment to (width, height) for the top right fragment. Therefore the uv coordinate ranges from (-1aspect, -1) to (1acpect, 1).

    vec2 uv = gl_FragCoord.xy/u_resolution.xy;
    uv.x *= u_resolution.x/u_resolution.y;
    

    The output color of the fragment shader depends on the uv coordiante:

    gl_FragColor = vec4(vec3(step( .3, length(uv))), 1.0);
    

    length(uv) calculates the length of the vector uv. The result increases circularly starting from point (0, 0). If you add a constant to the components of the coordinates (e.g. length(vec2(uv.x + 0.2, uv.y - 0.2)), the result still depends on the two components, resulting in a circle.
    This changes if you set one component of the coordinate uv to a constant value. Because then this component is no longer different for each fragment. Instead of setting uv.x = .2, you can also replace the expression by length(vec2(0.2, uv.y)). This way the result depends only on the y-component of the uv-coordinate, resulting in a bar instead of a circular shape.