Search code examples
cglslshader

Using Modulo on Screen Space Coordinates in GLSL Not Producing Expected Result


I suppose this is more of a math question than anything.

Here is a basic shader:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Time varying pixel color
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
    
    if(uv.x < .5) col = vec3(0.0,0.0,0.0);

    // Output to screen
    fragColor = vec4(col,1.0);
}

First we are normalizing our X coordinates between (0.0,0.1) with 0.0 being the far left of the screen and 1.0 being the far right. By turning all pixels with x coordinates < .5 black, I am simply masking half the screen in black. This results in the following:

enter image description here

If I use screen space coordinates I can achieve a similar result, the width of the actual screen is 800 pixels. So I can mask every pixel with an x < 400 with black by doing the following:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Time varying pixel color
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
    
    if(fragCoord.x < 400.) col = vec3(0.0,0.0,0.0);

    // Output to screen
    fragColor = vec4(col,1.0);
}

Which results in the same: enter image description here

Logically then, I should be able to use Modulo on the screen space coordinates to create stripes. By taking mod(fragCoord.x,10.0) and checking where the result is 0.0 I should be disabling any row of pixels where its x value is a factor of 10.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Time varying pixel color
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
    
    if(mod(fragCoord.x, 10.0) == 0.0) col = vec3(0.0,0.0,0.0);

    // Output to screen
    fragColor = vec4(col,1.0);
}

However, what I expect isn't happening:

enter image description here

Can somebody explain why I am not seeing rows of black pixels wherever x%10 == 0?


Solution

  • I assume fragCoord is set by gl_FragCoord.

    mod is a floating point operation and the values of gl_FragCoord are not integral. See Khronos OpenGL reference:

    By default, gl_FragCoord assumes a lower-left origin for window coordinates and assumes pixel centers are located at half-pixel centers. For example, the (x, y) location (0.5, 0.5) is returned for the lower-left-most pixel in a window.

    Therefore the result of the modulo operation will never be 0.0. Convert fragCoord.x to an integral value and use the % operator:

    if(mod(fragCoord.x, 10.0) == 0.0) col = vec3(0.0,0.0,0.0);

    if (int(fragCoord.x) % 10 == 0) col = vec3(0.0);