glsl での三角形の補間を二次関数で行う
はじめに
glsl の補間のモードには flat と smooth とがあります。 flat は一定の値での補間で smooth は線形な補間です。 この補間の機能はテクスチャの座標を決めたり、色のグラデーションに使われたりします。 この機能もう少し色々使えそうな気がして二次関数で補間するというのを試してみました。
実験用に書いたコードはこれです
https://github.com/bigsleep/interpolation-experiment
面積座標について
三角形要素内部での線形な補間は面積座標というものを使って表せます。 これは有限要素法やったことがある人は聞いたことがあると思います。
面積座標は三角形内部の点と各頂点を結んでできる三つの三角形の面積の比で表されます。
三角形内部でのあるパラメーターの値は各頂点での値と面積座標を掛けて足し合わせて求められます。
glsl で面積座標を使うには
バーテックスシェーダで vec3 の out パラメーター を用意して
頂点1では
頂点2では
頂点3では
として smooth モードで補間するとフラグメントシェーダーで in パラメーターとして使えます。
例えば下のようにシェーダを書くと三角形の縁の部分で色を変えることなどができます。
(glsl のバージョンによっては gl_VertexID を 3 で割った余りで頂点インデックスを計算することができると思うんですが webgl のためか上手くいかなかったので無理矢理な書き方になってしまってます。)
- バーテックスシェーダ
attribute float idx; varying vec3 L; void main() { L = vec3(0.0); if (idx == 0.0) { L[0] = 1.0; } else if (idx == 1.0) { L[1] = 1.0; } else { L[2] = 1.0; } gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
- フラグメントシェーダ
varying vec3 L; void main() { float a = 0.1; gl_FragColor = (L[0] <= a || L[1] <= a || L[2] <= a) ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(1.0); }
この図では三角形二つ表示しています。
三角形二次要素
有限要素法の本を見返してみたところ三角形二次要素についても書かれていました。
三角形二次要素は二次関数を使うため節点が六個必要になります。
三つの頂点に加えて辺の中央に残り三つの節点を選ぶのが一般的なようです。
有限要素法の本によると二次要素の場合の補間関数は面積座標を使って下のように表せます。 (プログラムにする都合により添字の順番など変えています。)
これを分割してバーテックスシェーダの の三つの vec3 out パラメーターとして表します。
頂点1では
頂点2では
頂点3では
フラグメントシェーダで パラメーターから補間値を計算します。
シェーダ
- バーテックスシェーダ
attribute float idx; attribute float ui; attribute float uj; varying vec3 L; varying vec3 v; varying vec3 w; void main() { L = vec3(0.0); if (idx == 0.0) { L[0] = 1.0; v[0] = ui; w[0] = uj; } else if (idx == 1.0) { L[1] = 1.0; v[1] = ui; w[1] = uj; } else { L[2] = 1.0; v[2] = ui; w[2] = uj; } gl_Position = projectionMatrix * modelViewMatrix vec4(position, 1.0); }
- フラグメントシェーダ
varying vec3 L; varying vec3 v; varying vec3 w; void main() { float u = 0.0; u += v[0] * (2.0 * L[0] - 1.0) + 4.0 * w[0] * L[1]; u += v[1] * (2.0 * L[1] - 1.0) + 4.0 * w[1] * L[2]; u += v[2] * (2.0 * L[2] - 1.0) + 4.0 * w[2] * L[0]; gl_FragColor = vec4(vec3(u), 1.0); }
出力結果
参考
学生のときに読んだ 有限要素法概説 という本を参考にさせていただきました。
三角形二次要素はよく使うと思われるので他のネット上の資料や本にも書かれていると思います。
まとめ
面積座標を利用して glsl で三角形の補間を二次関数でやってみました。
いまいちあってるか自信がないですがこの方法でもできるのではないかと思います。
ただこの方法で効率がいいかなどはよくわかってません。
実際に使えそうなところとしては有限要素法などの計算の結果を表示する場合などがあると思います。