Search code examples
mathvectorglslshadervec

How did it get converted into 1 line of code from 3 lines? Remapping uv and fixing aspect ratio in shaders


How would you get from this

vec2 uv = fragCoord/iResolution.xy; // <0, 1>
uv -= 0.5; // <-0.5,0.5>
uv.x *= iResolution.x/iResolution.y; // fix aspect ratio

to this?

vec2 uv = (fragCoord - .5 * iResolution.xy) / iResolution.y; // Condense 3 lines down to a single line!

Well, I tried breaking it down into components

((fragCoord.x-0.5) / iResolution.x) * (iResolution.x / iResolution.y)

((fragCoord.y-0.5) / iResolution.y)


Solution

  • Let's add a 4th line:

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

    Notice that iResolution.y/iResolution.y == 1, so the line we added changes nothing. However, it opens the possibility to simplify the code. We can now combine the 3rd and the 4th line by operating on two-component vectors:

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

    Combining it all together into one algebraic expression turns it into:

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

    Now we can move iResolution.xy inside the parentheses (distributive law of multiplication):

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

    And, of course, dividing fragCoord by iResolution.xy cancels out with multiplying it by iResolution.xy, so we arrive at the one liner you had:

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