線形補間を用いたグラデーションの実装
- フラグメントシェーダー
前回の記事「グラデーションの実装」ではThree.jsのUV座標を使用してグラデーションを実装した。
varying vec2 vUv;
void main () {
float red = vUv.x;
gl_FragColor = vec4(red, 0.0, 0.0, 1.0);
}
上記では黒から赤へのグラデーションであったが、今回は線形補間を利用して2色以上のグラデーションを実装してみる。
線形補間に関しては「正規化・線形補間・マップ|クリエイティブコーディングの教科書」をみるとわかりやすい。
ついでに本記事でもざっくりと説明してみる。点aと点bがある時に、この2点を結ぶことを補間というわけだか、くわえて結んだ線が直線の時を線形補間という。この時の線分abは一次関数で表すことが可能だが(線形補間は1次補間とも呼ばれる)、GLSLにおいてはmix
を使うことで表現できる。
mix(a, b, t)
は、線分ab上をt : 1 - t
に内分する点Tの位置を計算してくれることとなる。たとえば点aを(0, 0)
、点bを(4, 8)
とすれば以下のようになる。
点a = (0, 0)
点b = (4, 8) とする
// t = 0 の時
mix(a, b, 0) = (0, 0)
// t = 0.25 の時
mix(a, b, 0.25) = (1, 2)
// t = 0.5 の時
mix(a, b, 1) = (2, 4)
// t = 1 の時
mix(a, b, 1) = (4, 8)
2色の線形補間
上記を踏まえてから、赤から青に変化するグラデーションを実装してみる。
fragmentShader
3色の線形補間
次に赤から緑、緑から青になるように実装してみる。
fragmentShader
上記のコードはざっくり以下のような感じである。
// 赤、緑、青のvec3型の配列を宣言
vec3 red = vec3(1.0, 0.0, 0.0);
vec3 green = vec3(0.0, 1.0, 0.0);
vec3 blue = vec3(0.0, 0.0, 1.0);
vec3[3] rgb = vec3[](
red, green, blue
);
// [0 ~ 1]を[0 ~ 2]に変換する
float doubleUv = vUv.x * 2.0;
// 配列のindexはint型である必要がある
int index = doubleUv < 1.0 ? 0 : 1;
// doubleUvが[0 ~ 2]なのでfractは0以上1未満を2回繰り返す
// →赤から緑、緑から赤
vec3 mixed = mix(rgb[index], rgb[index+1], fract(doubleUv));
//...
4色のバイリニア補間(双線形補間)
最後に上下左右の4色でグラデーションするためにバイリニア補間(双線形補間)というものを使ってみる。
fragmentShader
バイリニア補間についてはあまり理解しきれていないので、本記事では詳しく触れないが(かわり参考を載せておく)、以下のようなコードを書いている。
// 4色の宣言
vec3 red = vec3(1.0, 0.0, 0.0);
vec3 green = vec3(0.0, 1.0, 0.0);
vec3 blue = vec3(0.0, 0.0, 1.0);
vec3 yellow = vec3(1.0, 1.0, 0.0);
// 上半分でx軸方向に線形補間(赤→緑)
vec3 mixedTop = mix(red, green, vUv.x);
// 上半分でx軸方向に線形補間(青→黄色)
vec3 mixedBottom = mix(blue, yellow, vUv.x);
// y軸方向にmixedTopとmixedBottomを線形補間
// y軸は下が0で上が1となることに気をつける
vec3 mixed = mix(mixedBottom, mixedTop, vUv.y);