前置き
[前回のノート](/articles/7 种 webgl 图元-webgl 笔记 6/) で、7 種類の図元を認識し、パラメータを変更することで異なるものを描画できることを学びましたが、具体的な詳細は十分に説明されていませんでした。これはシェーダーの動作原理から話す必要があり、varying 変数は頂点シェーダーとフラグメントシェーダー間のデータチャネルとして、避けられない話題です
一.varying 変数
以前に 2 種類のシェーダー変数を説明しました:attribute 変数、uniform 変数。varying 変数は最後の 1 種類のシェーダー変数で、前 2 つより少し複雑です。内挿(interpolate)のプロセスがあるためです
varying 変数の作用は頂点シェーダーからフラグメントシェーダーへ値を伝達することです。varying 変数は float タイプのみ可能です。フラグメントシェーダー中にも同名の varying 変数を宣言すれば、頂点シェーダーが該変数に代入した値は自動的にフラグメントシェーダーに伝達されます(フラグメントシェーダー中の同名 varying 変数に代入する前に、内挿のプロセスがあり、1.0 が伝達されても必ずしも 1.0 ではありません)
注意:頂点シェーダー中の varying 変数の値は直接伝達されず、まず内挿が行われます。内挿は補間アニメーションのようなものです
二.内挿(interpolate)
補間値は、データが不足している場合にのみ必要です。例えば、一連の散点を滑らかな曲線で接続したい場合、隣接する既知点の間に多くの点が不足しており、この時に内挿を通じて不足しているデータを埋め、最終的に滑らかな曲線上の既知点以外のすべての点は補間値によって得られます
例えば Photoshop のカスタムグラデーションで、私たちは数点の色を設定するだけで自動的に 1 本全体のグラデーション帯を生成できます。これら数点の間の色はすべて内蔵補間アルゴリズムによって得られます
varying 変数の値がフラグメントシェーダーに伝達される前に行われる補間プロセスは内挿と呼ばれます。同様に、私たちは内挿を利用してグラデーションを生成することもできます
三.グラデーション三角形
フラグメントシェーダー中に頂点シェーダーの varying 変数と同名の varying 変数を宣言すれば、値は自動的に伝達されます(もちろん、内挿のプロセスがあります)
###1.シェーダーソースプログラム
フラグメントシェーダー中に同名 varying 変数を宣言します。具体的には以下の通り:
// 頂点シェーダーソースプログラム
var vsSrc = 'attribute vec4 a_Position;' +
'attribute vec4 a_Color;' +
'varying vec4 v_Color;' + // varying 変数を宣言
'void main() {' +
'gl_Position = a_Position;' + // 座標を設定
'gl_PointSize = 7.0;' + // サイズを設定
'v_Color = a_Color;' + // varying 変数に値を代入
'}';
// フラグメントシェーダーソースプログラム
//!!! 浮動小数点精度を宣言する必要があります。否则报错 No precision specified for (float)
var fsSrc = 'precision mediump float;' +
'varying vec4 v_Color;' + // 同名 varying 変数を宣言
'void main() {' +
'gl_FragColor = v_Color;' + // 色を設定
'}';
注意:varying 変数に直接値を代入することはできません。attribute 変数を通じて外部値を受け取り、頂点シェーダー内部で varying 変数に値を代入する必要があります
###2.単色三角形とグラデーション三角形
鍵は 3 つの頂点の色が一致するかどうかです。実際のプロセスは以下の通り:
- 頂点情報を読み取る(座標、色など)
頂点シェーダーを実行し、1 個の頂点の関連データを読み取る
- 図形組立(点を描くか線を描くか三角を描くか)
孤立した頂点座標を幾何図形に組立する。図形のカテゴリは gl.drawArrays の最初のパラメータによって決定される。例えば gl.POINTS, gl.TRIANGLES
- ラスタライズ(どのピクセルに着色する必要があるかを確定)
組立好的幾何図形をフラグメントに変換し、ベクトルの幾何図形をラスタライズされたフラグメント(ピクセル)に変換する
- フラグメントシェーダーを実行(着色)
各フラグメントに着色する
- 最初のステップに戻り、読み終われば終了し、終わらなければ次の頂点を読み取ってもう一度行う
したがって頂点シェーダーは頂点ごとに実行され、フラグメントシェーダーはフラグメントごとに実行されます。2 重ループのようなもので、外層は頂点を遍历し、内層はフラグメントを遍历します。以上のプロセスは下図の通り:
[caption id="attachment_913" align="alignnone" width="773"]
webgl-vertex-shader-execution[/caption]
[caption id="attachment_914" align="alignnone" width="738"]
webgl-varying[/caption]
以前の DEMO では色はすべてフラグメントシェーダー中にハードコーディングされていました。例えば gl_FragColor = vec4(1.0, 0.0, 1.0, 0.75)。したがって描画されたすべてのものは単色でした。しかしより科学的な方法は頂点色を頂点シェーダーに伝達し、頂点色に基づいて各フラグメントの色を内挿することです。例えば 1 本の孤立線分を描画する場合、2 つの同色頂点の間のフラグメントは内挿後すべてその色になり、2 つの異色頂点の間のフラグメントは内挿後他の色が現れます
###3.グラデーション三角形の描画
3 つの頂点を異なる色に設定します。以下の通り:
var arrVtx = new Float32Array([
// x, y, r, g, b
-0.5, 0.5, 1.0, 0.0, 1.0, 1.0, // 赤色
0.5, 0.5, 0.0, 1.0, 0.0, 1.0, // 緑色
-0.5, -0.5, 0.0, 0.0, 1.0, 1.0 // 青色
]);
//...頂点配列をバッファに書き込む
// 点を描画
gl.drawArrays(gl.POINTS, 0, arrVtx.length / 6);
setTimeout(function() {
gl.clear(gl.COLOR_BUFFER_BIT);
// 三角形を描画
gl.drawArrays(gl.TRIANGLES, 0, arrVtx.length / 6);
}, 2000);
まず 3 つの孤立点(赤緑青)を描画し、2 秒後に三角形を描画すると、グラデーション三角形が現れます。これも gl_PointSize の設定は draw point 時のみ有効で、三角形を描画すると自動的に該値を無視することを説明しています
四.DEMO
上記のコードを含む完全な例は、以下を参照してください:
-
赤緑青グラデーション三角形:http://www.ayqy.net/temp/webgl/varying/index.html
-
赤色グラデーション三角形:http://www.ayqy.net/temp/webgl/fragment-shader-detail/index.html
座標に基づいてフラグメント色を設定し、フラグメントシェーダーがフラグメントごとに実行されるプロセスを検証
注意:フラグメントシェーダーの内蔵変数 gl_FragCoord はフラグメントの座標情報 (gl_FragCoord.x, gl_FragCoord.y) を保存しています。出力できる場合、フラグメントシェーダーが頂点ごとに実行されるプロセスが発見できますが、API は console に情報を出力する方法を提供していません。フラグメント座標に基づいて色を設定することで検証できます
五.まとめ
varying 変数はグラデーション効果を実現できるだけでなく、それを利用して様々な入手できない数値を内挿することもできます。例えばフラグメントのワールド座標、フラグメントの光源座標系��の座標など、非常に有用です
私たちは現在カラー図形を描画できます。色に関連するもう 1 つの特性はテクスチャ(テクスチャマッピング)です。これは次回のノートの内容です
参考資料
- 『WebGL プログラミングガイド』
コメントはまだありません