Search code examples
glslfragment-shadershadertoy

Shadertoy - fragCoord vs iResolution vs fragColor


I'm fairly new to Shadertoy and GLSL in general. I have successfully duplicated numerous Shadertoy shaders into Blender without actually knowing how it all works. I have looked for tutorials but I'm more of a visual learner.

If someone could explain or, even better, provide some images that describe the difference between fragCoord, iResolution, & fragColor. That would be great!

I'm mainly interested in the Numbers. Because I use Blender I'm used to the canvas being 0 to 1 -or- -1 to 1

This one in particular has me a bit confused.

vec2 u = (fragCoord - iResolution.xy * .5) / iResolution.y * 8.;

example

I can't reproduce the remaining code in Blender without knowing the coordinate system.

Any help would be greatly appreciated!


Solution

  • It is normal, you cannot reproduce this code in blender without knowing the coordinate system.

    The Shadertoy documentation states:

    Image shaders implement the mainImage() function to generate procedural images by calculating a color for each pixel in the image. This function is invoked once in each pixel and the host application must provide the appropriate input data and retrieve the output color to assign it to the corresponding pixel on the screen. The signature of this function is:

    void mainImage( out vec4 fragColor, in vec2 fragCoord);

    where fragCoord contains the coordinates of the pixel for which the shader must calculate a color. These coordinates are counted in pixels with values from 0.5 to resolution-0.5 over the entire rendering surface and the resolution of this surface is transmitted to the shader via the uniform iResolution variable.

    Let me explain.

    The iResolution variable is a uniform vec3 which contains the dimensions of the window and is sent to the shader with some OpenGL code.

    The fragCoord variable is a built-in variable that contains the coordinates of the pixel where the shader is being applied.

    More concretely:

    • fragCoord : is a vec2 that is between 0 > 640 on the X axis and 0 > 360 on the Y axis
    • iResolution : is a vec2 with an X value of 640 and a Y value of 360

    A quick note on how vectors work in OpenGL:

    • if you have also a hard time understanding how vector work in OpenGL, I highly recommend to read the answer of Homan below, a very useful introduction to OpenGL swizzling.

    Standard normalize uv

    This image was calculated with the following code:

    // Normalized pixel coordinates (between 0 and 1)
    vec2 uv = fragCoord/iResolution.xy;
    
    // Set R and G values based on position
    vec3 col = vec3(uv.x,uv.y,0);
    
    // Output to screen
    fragColor = vec4(col,1.0);
    

    The output ranges from 0,0 in the lower-left and 1,1 in the upper-right. This is the default lower-left windows space set by OpenGL.


    Windows centred uv This an image was calculated with the following code:

    // Normalized pixel coordinates (between -0.5 and 0.5)
    vec2 uv = (fragCoord - iResolution.xy * 0.5)/iResolution.xy;
    
    // Set R and G values based on position
    vec3 col = vec3(uv.x,uv.y,0);
    
    // Output to screen
    fragColor = vec4(col,1.0);
    

    The output ranges from -0.5,-0.5 in the lower-left and 0.5,0.5 because in the first step we subtract half of the window size [0.5] from each pixel coordinate [fragCoord]. You can see the effect in the way the red and green values don't kick into visibility until much later.

    You might also want to normalize only the y axis by changing the first step to

    vec2 uv = (fragCoord - iResolution.xy * 0.5)/iResolution.y;
    

    Depending our your purpose the image can seem strange if you normalize both axes so this is a possible strategy.


    ceil() uv to see more clearly

    This an image was calculated with the following code:

    // Normalized pixel coordinates (between -0.5 to 0.5)
    vec2 uv = (fragCoord - iResolution.xy * 0.5)/iResolution.xy;
    
    // Set R and G values based on position using ceil() function
    // The ceil() function returns the smallest integer that is greater than the uv value
    vec3 col = vec3(ceil(uv.x),ceil(uv.y),0);
    
    // Output to screen
    fragColor = vec4(col,1.0);
    

    The ceil() function allows us to see that the center of the image is 0, 0.


    As for the second part of the Shadertoy documentation:

    The output color is returned in fragColor as a four-component vector, the last component being ignored by the client. The result is retrieved in an "out" variable in anticipation of the future addition of several rendering targets.

    Really all this means is that fragColor contains four values that are shopped to the next stage in the rendering pipeline. You can find more about in and out variables here.

    The values in fragColor determine the color of the pixel where the shader is being applied.

    If you want to learn more about shaders these are some good starting places:

    the book of shader - uniform
    learn OpenGL - shader