正規化は、一定のルールに基づいて、データを都合の良い形に整えること。
GLSL の場合、色は[0, 1]区間、座標は[0, 1]や[-1, 1]などの区間内の数値として扱うことが多い。
そのため、ここでいう正規化とは、ある値を[0, 1]範囲に収まる値(割合)に変換することだとする。
[a, b]範囲内に A という値がある。
このとき、[a, b]区間全体に対する A の割合は、
より、となるので、これを関数化すると、
float norm(float v, float min, float max) {
return (v - min) / (max - min);
}
範囲と割合を渡すと、その割合の位置にある値を返す機能を線形補間という。
範囲に割合をかければ、その割合の「位置」は求まる。
範囲の下限が 0 でないならば、その位置の「値」は下限を足したものになるはずだ。
float lerp(float min, float max, float t) {
return min + (max - min) * t;
}
ちょっと式変形すると、t : (1 - t)
という比が見えてくる。
min + max * t - min * t
= min * 1 - min * t + max * t
= (1 - t) * min + t * max
この lerp 関数にあたるのが、GLSL の mix 関数なので、自前で実装する必要はない。
GLSL を触っていると、ある範囲内での位置(値)が、別の範囲内ではどの位置(値)に対応するのか、を知りたくなる機会がある。
例えば、[0, 100]区間内の 50 の位置は、[0, 10]区間内での 5 の位置に対応する。
[a, b]範囲内の A の位置が、[x, y]範囲内の X という位置に対応するとする。
まず、[a, b]区間に対する A の割合 M は、norm(A, a, b)
で求まる。
そして、[x, y]範囲内で、割合が M となる値は、lerp(x, y, M)
(GLSL ではmix(x, y, M)
)で求まる。
float map(float v, float min1, float max1, float min2, float max2) {
return mix(min2, max2, norm(v, min1, max1));
}