1
$\begingroup$

Here is a shader in GLSL that visualizes the normalized pixel coordinates (from 0 to 1):

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

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

Output:

enter image description here

So we have (0,0) at bottom left, (1,0) at top left, (1,1) at top right, and (1,0) at bottom right.

Pretty simple.

But now, if we change the line vec2 lv = uv to vec2 lv = fract(uv*2.);, we introduce a 2x2 grid:

enter image description here

Why does that happen?

Previously, the top center was between green and yellow. When we had uv = (0.5,1), but then we do lv = fract((0.5,1)*2) = fract((1,2)) = (0,0), so it just becomes black? But there's no black at the top of the new image.

TLDR: I don't understand why when we do lv = fract(uv*K) it introduces a KxK grid into the output.

$\endgroup$

1 Answer 1

3
$\begingroup$

Multiplying uv by K scales it from a 0–1 range to a 0–K one. As you’re noting, the fract operation takes the result of that and removes the whole-number portion of the value, resulting in a [0 1) result. The values your shader outputs are never actually hitting 100% brightness in any channel (…within the limits of the 8-bit output, of course), because when the value becomes ≥ 1 it wraps around again. If you looked slightly off that top edge, say with lv = fract((uv + vec2(0.0, 0.1)) * K), you’d see the black corner you’re looking for.

screenshot of the same 2×2 UV gradient, slightly shifted to show the pattern repeating past the top edge

Another way of looking at it would be to graph a 1-dimensional value. Here’s y = x:

a graph of y = x, a diagonal line with 45° slope

…and here’s y = fract(2x):

a graph of y = fract(2x), a repeating diagonal line pattern with a steeper 63°ish slope

Just like the 2D color values you’re producing, the first extends indefinitely along that one line, and the second has a sawtooth pattern that repeats each time the value being fed into fract crosses a whole-number threshold.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.