みさご解体新書

gl_FragCoordの正規化

解説/アルゴリズム

vec2 uv = (gl_FragCoord.xy * 2.0 - vResolution) / min(vResolution.x, vResolution.y);

gl_FragCoord はよくこの形で正規化されることが多い。

gl_FragCoord には Canvas のピクセル座標が格納されている。

ただし、y 座標は上に行くほど大きくなるので、左下が (0, 0) 、右上が (キャンバスの幅, キャンバスの高さ) になる。

この gl_FragCoord を クリップ空間と同じの -1.0 ~ 1.0 の範囲に正規化するのが目的となる。

まずは Canvas の縦横が同じサイズだった場合について考えてみる。

vec2 uv = gl_FragCoord.xy / vResolution * 2.0 - 1.0;

gl_FragCoord を Canvas のサイズで割ることで 0.0 ~ 1.0 の範囲に変換する。

この範囲を 2 倍することで、0.0 ~ 2.0 の範囲に変換する。

更にこの範囲から -1.0 を引くことで、 -1.0 ~ 1.0 の範囲に変換することができた。

次は Canvas の縦横が異なるサイズだった場合について考えてみる。

vec2 uv = gl_FragCoord.xy / vResolution.y;

縦横のサイズが異なる場合で縦横比を維持したい場合は、Canvas の幅か高さどちらか一方で割らなければならない。

ここでは高さで割ることにする。

vec2 uv = gl_FragCoord.xy / vResolution.y * 2.0 - vec2(vResolution.x / vResolution.y, 1.0);

vResolution.y で割って正規化する場合、縦のサイズは 1 だが、横は vResolution.x / vResolution.y となる。 なので、 -1.0 の部分を、vec2(vResolution.x / vResolution.y, 1.0) にする必要がある。

各項の vResolution.y で割るところを括りだすと、

vec2 uv = (gl_FragCoord.xy * 2.0 - vec2(vResolution.x, vResolution.y)) / vResolution.y;

となり、 vec2(vResolution.x, vResolution.y) はただの vResolution のことなので、

vec2 uv = (gl_FragCoord.xy * 2.0 - vResolution) / vResolution.y;

と書くことができる。