WebGL Vering 変数の役割と補間処理、Varing の実行に関わるグラフィックス アセンブリ、ラスタライズ、カラー補間、フラグメント シェーダ実行メカニズムなどの詳細な説明

目次

序文

WebGL または OpenGL では、「可変」は、頂点シェーダーとフラグメント シェーダーの間でデータを渡すために使用される特殊なタイプの変数です。これにより、データを頂点シェーダーで処理し、その後の計算のためにフラグメント シェーダーで使用できるようになります。 

3 つのドットに色を付ける 

編集

カラフルな 3 つのドットのサンプルコード

さまざまな変数を使用するための仕様 

彩色三角形

ジオメトリのアセンブリとラスタライズ

赤い三角のサンプルコード

頂点座標 --> グラフィックスアセンブリ --> ラスタライズ --> フラグメントシェーダの実行

エレメント組立工程

ラスタライズ処理

頂点シェーダーとフラグメントシェーダー間のグラフィックスのアセンブリとラスタライズのプロセスの詳細な説明

ステップ 1: 頂点シェーダーを実行し、バッファ オブジェクトの最初の座標 (0.0, 0.5) が属性変数 a_Position に渡されます。頂点の座標が gl_Position に割り当てられると、その座標はグラフィックス アセンブリ領域に入り、そこに一時的に保存されます。x コンポーネントと y コンポーネントを a_Position に明示的に割り当てただけであることを覚えておく必要があります。そのため、z コンポーネントと w コンポーネントにはデフォルト値が割り当てられました。グラフィックス アセンブリ領域に入る座標は、実際には (0.0, 0.5, 0.0, 1.0) です。

ステップ 2: 頂点シェーダーを再度実行し、同様に 2 番目の座標 (-0.5、-0.5、0.0、1.0) を渡し、アセンブリ領域に保存します。

ステップ 3: 頂点シェーダーを 3 回目に実行し、3 番目の座標 (0.5、-0.5、0.0、1.0) を渡してアセンブリ領域に保存します。これで、頂点シェーダーの実行が終了し、3 つの頂点座標すべてがアセンブリ領域内にあります。

ステップ 4: グラフィックスの組み立てを開始します。入力ポイントの座標を使用して、gl.drawArrays() の最初のパラメーター情報 (gl.TRIANGLES) に基づいてアセンブルする方法を決定します。この例では、3 つの頂点を使用して三角形を組み立てます。

ステップ 5: 画面に表示される三角形はフラグメント (ピクセル) で構成されているため、グラフィックスもフラグメントに変換する必要があります。このプロセスはラスタライズと呼ばれます。ラスター化後、この三角形を構成するすべてのフラグメントが得られます。上の画像の最後のステップでは、ラスター化後に三角形を形成するフラグメントを確認できます。

フラグメントシェーダーを呼び出す

実験を行う: フラグメントの位置に基づいてフラグメントの色を決定します。

gl.drawingBufferWidth / gl.drawingBufferHeight

ディスプレイ効果

さまざまな変数の役割と補間プロセス

さまざまな変数の動作

さまざまな変数の補間編集編集

色の値の補間

要約する 


序文

WebGL または OpenGL では、「可変」は、頂点シェーダーとフラグメント シェーダーの間でデータを渡すために使用される特殊なタイプの変数です。これにより、データを頂点シェーダーで処理し、その後の計算のためにフラグメント シェーダーで使用できるようになります。 

3 つのドットに色を付ける 

カラフルな 3 つのドットのサンプルコード

// 顶点着色器
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'varying vec4 v_Color;\n' + // varying 变量
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 10.0;\n' +
  '  v_Color = a_Color;\n' +  // 将数据传给片元着色器
  '}\n';

// 片元着色器
var FSHADER_SOURCE =
  'precision mediump float;\n' + // 设置varing精度
  'varying vec4 v_Color;\n' +    // 从顶点着色器接受数据
  'void main() {\n' +
  '  gl_FragColor = v_Color;\n' +
  '}\n';

function main() {
  var canvas = document.getElementById('webgl');
  var gl = getWebGLContext(canvas);
  // 设置顶点的坐标和颜色
  var n = initVertexBuffers(gl);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
  var verticesColors = new Float32Array([
    // 顶点坐标和颜色
     0.0,  0.5,  1.0,  0.0,  0.0, 
    -0.5, -0.5,  0.0,  1.0,  0.0, 
     0.5, -0.5,  0.0,  0.0,  1.0, 
  ]);
  var n = 3; // 顶点数量

  // 创建缓冲区对象
  var vertexColorBuffer = gl.createBuffer();  
  if (!vertexColorBuffer) {
    console.log('Failed to create the buffer object');
    return false;
  }

  // 将顶点坐标和颜色写入缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);

  var FSIZE = verticesColors.BYTES_PER_ELEMENT;
  // 获取a_Position的存储位置,分配缓冲区并开启
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0);
  gl.enableVertexAttribArray(a_Position);  // 开启变量

  // 获取a_Color的存储位置,分配缓冲区并开启
  var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
  gl.enableVertexAttribArray(a_Color);  // 开启缓冲区分配

  return n;
}

さまざまな変数を使用するための仕様 

 頂点シェーダーでは、カラー データを受け取る属性変数 a_Color を宣言し (4 行目)、次に、カラー値をフラグメント シェーダーに渡す役割を担う新しい可変変数 v_Color を宣言します (5 行目)。可変変数は float 型 (および関連する vec2、vec3、vec4、mat2、mat3、および mat4) のみであることに注意してください。

a_Color 変数の値を、前に宣言した v_Color 変数に直接割り当てます (9 行目)。 

では、フラグメント シェーダーはこの変数をどのように受け取るのでしょうか? 答えは簡単です。フラグメント シェーダーで可変変数 (頂点シェーダーの可変変数と同じ名前) を宣言するだけです。

WebGL では、頂点シェーダーとフラグメント シェーダーに同じ型と名前の可変変数がある場合、次の図に示すように、頂点シェーダーによって変数に割り当てられた値が自動的にフラグメント シェーダーに渡されます。 

したがって、頂点シェーダー (9 行目) によって v_Color 変数に割り当てられた値は、フラグメント シェーダーの v_Color 変数に渡され、フラグメント シェーダーは v_Color を gl_FragColor に割り当てます。これにより、各頂点の色が変更されます ( 行目) 17)。 

配列 verticesColor には 2 つの異なるタイプのデータ (座標と色) があります。現在の色には 3 つのコンポーネント値があるため、各頂点が占めるバイト数は FSIZE*5 です。対応する gl.vertexAttribPointer() 関数の stride パラメーターと offset パラメーターを変更する必要があります (53 行目と 58 行目)。

最後に描画コマンド(27行目)が実行され、ブラウザ上に赤、青、緑の3点が描画されます。

彩色三角形

gl.drawArrays() 関数の最初のパラメータを gl.TRIANGLES に変更するとどうなるかを見てみましょう(27 行目)

プログラムの結果は下図のように、赤、緑、青の3つの角を持ち、色の滑らかな変化を持つ三角形を描画します。

パラメータを 1 つ変更しただけで、プログラムの結果は、異なる色の 3 つの孤立点から、色の滑らかな変化を伴う三角形に変わりました。結局何が起こったのですか?

ジオメトリのアセンブリとラスタライズ

わかりやすくするために、赤い三角形のコードを説明します。

赤い三角のサンプルコード

 initVertexBuffers() 関数でバッファ オブジェクトに頂点座標を書き込み (50 行目と 52 行目)、そのバッファ オブジェクトを a_Position 変数に割り当てます (74 行目)。最後に、gl.drawArrays() が呼び出され、頂点シェーダーが実行されます (行 46)。頂点シェーダーが実行されると、バッファー内の 3 つの頂点座標が a_Position 変数 (4 行目) に渡され、gl_Position (6 行目) に割り当てられるため、WebGL システムは頂点座標に従って描画できるようになります。フラグメント シェーダーでは、赤色の RGBA 値 (1.0、0.0、0.0、1.0) を gl_FragColor に割り当て、赤色の三角形を描画します。

しかし、これまでのところ、これがどのように行われるのかまだ理解していませんか?gl_Position に三角形の 3 つの頂点の座標を指定した場合、フラグメント シェーダーはいわゆるフラグメントごとの操作をどのように実行できるのでしょうか?

次の図は、gl_Position に 3 つの頂点の座標を与えるプログラムですが、この 3 点が三角形の 3 つの頂点であると誰が判断するのでしょうか。結局のところ、三角形の内部を埋めるためにどのピクセルに色を付ける必要があるのか​​を誰が決定するのでしょうか? フラグメント シェーダーの呼び出しは誰が担当しますか? フラグメント シェーダーは各フラグメントをどのように処理しますか?

頂点座標 --> グラフィックスアセンブリ --> ラスタライズ --> フラグメントシェーダの実行

 頂点シェーダーとフラグメント シェーダーには、次の 2 つのステップがあります。

  • エレメント組立工程

  このステップのタスクは、孤立した頂点座標を幾何学的形状に組み立てることです。ジオメトリのカテゴリは、gl.drawArrays() 関数の最初のパラメータによって決定されます。

  • ラスタライズ処理

  このステップのタスクは、組み立てられたジオメトリをフラグメントに変換することです。

上の図に示すように、gl_Position は実際には幾何学的形状のアセンブリ段階の入力データです。組み立てられた基本グラフィックス (点、線、および面) はプリミティブとも呼ばれるため、幾何学的図形の組み立てプロセスはプリミティブアセンブリプロセスとも呼ばれます。 

頂点シェーダーとフラグメントシェーダー間のグラフィックスのアセンブリとラスタライズのプロセスの詳細な説明

ステップ 1: 頂点シェーダーを実行し、バッファ オブジェクトの最初の座標 (0.0, 0.5) が属性変数 a_Position に渡されます。頂点の座標が gl_Position に割り当てられると、その座標はグラフィックス アセンブリ領域に入り、そこに一時的に保存されます。x コンポーネントと y コンポーネントを a_Position に明示的に割り当てただけであることを覚えておく必要があります。そのため、z コンポーネントと w コンポーネントにはデフォルト値が割り当てられました。グラフィックス アセンブリ領域に入る座標は、実際には (0.0, 0.5, 0.0, 1.0) です。

ステップ 2: 頂点シェーダーを再度実行し、同様に 2 番目の座標 (-0.5、-0.5、0.0、1.0) を渡し、アセンブリ領域に保存します。

ステップ 3: 頂点シェーダーを 3 回目に実行し、3 番目の座標 (0.5、-0.5、0.0、1.0) を渡してアセンブリ領域に保存します。これで、頂点シェーダーの実行が終了し、3 つの頂点座標すべてがアセンブリ領域内にあります。

ステップ 4: グラフィックスの組み立てを開始します。入力ポイントの座標を使用して、gl.drawArrays() の最初のパラメーター情報 (gl.TRIANGLES) に基づいてアセンブルする方法を決定します。この例では、3 つの頂点を使用して三角形を組み立てます。

ステップ 5: 画面に表示される三角形はフラグメント (ピクセル) で構成されているため、グラフィックスもフラグメントに変換する必要があります。このプロセスはラスタライズと呼ばれます。ラスター化後、この三角形を構成するすべてのフラグメントが得られます。上の画像の最後のステップでは、ラスター化後に三角形を形成するフラグメントを確認できます。

上の図では、説明のために 10 個の断片のみを示しています。実際、フラグメントの数は、三角形が最終的に画面上でカバーするピクセルの数になります。gl.drawArrays() の最初のパラメータが変更されると、ステップ 4 のグラフィックス アセンブリとステップ 5 のフラグメントの数と位置がそれに応じて変更されます。たとえば、このパラメータが gl.LINE の場合、プログラムは最初の 2 点を使用して線分を組み立て、3 番目の点を破棄します。gl.LINE_LOOP の場合、プログラムは 3 つの点を折り曲げ接続端に組み立てます。 end. 線分を抽出し、中空の三角形をラスタライズします (中間ピクセルを生成せずに)。

フラグメントシェーダーを呼び出す

ラスター化プロセスが完了すると、プログラムはフラグメントごとにフラグメント シェーダーの呼び出しを開始します。次の図では、フラグメント シェーダが 10 回呼び出され、呼び出されるたびに 1 つのフラグメントが処理されます (次の図では、わかりやすくするために中間ステップを省略しています)。フラグメントごとに、フラグメント シェーダはフラグメントのカラーを計算し、それをカラー バッファに書き込みます。最後のフラグメントがステップ 15 で処理されるまで、ブラウザには最終結果が表示されます。

以下に示すように、赤い三角コードのフラグメント シェーダーは、各フラグメントの色を赤に割り当てます。したがって、ブラウザは赤い三角形を描画します。

実験を行う: フラグメントの位置に基づいてフラグメントの色を決定します。

これは、フラグメント シェーダが各フラグメントに対して 1 回実行されることを証明しています。ラスタライズ プロセスによって生成されたフラグメントはすべて座標情報を持っています。フラグメント シェーダーが呼び出されるとき、座標情報もフラグメントとともに渡されます。フラグメント シェーダーの組み込み変数を通じてフラグメントの座標にアクセスできます。(以下の表に示すとおりです)。 

 フラグメント シェーダがフラグメントごとに実行されることを証明するために、以下に示すように、元の赤い三角プログラム (gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0)) の 12 行目を変更しました。

フラグメント シェーダのプログラム コードから、三角形の各フラグメントの色、その赤の成分、および青の成分が、フラグメントの位置に基づいて計算されることがわかります。Canvas の Y 軸方向は WebGL システムの Y 軸方向と逆であり、WebGL の色コンポーネントの値の範囲は 0.0 ~ 1.0 であるため、Y 軸座標を < の高さで割る必要があることに注意してください。 Canvas> 要素 (400 ピクセル) を使用して、0.0 ~ 1.0 に圧縮します。gl.drawingBufferWidth (カラー バッファの幅)gl.drawingBufferHeight (カラー バッファの高さ)の値をユニフォーム変数 u_Width と u_Height に渡します下の色付きの三角形はプログラムの結果を示しています。三角形、ピクセルの色はピクセルの位置によって決定され、左上から右下へのグラデーション効果を示しています。 

gl.drawingBufferWidth / gl.drawingBufferHeight

  gl.uniform1f(u_Width, gl.drawingBufferWidth); // 颜色缓冲区的宽度,下面同理 高度
  gl.uniform1f(u_Height, gl.drawingBufferHeight);

ディスプレイ効果

フラグメントの色は座標位置に依存するため、フラグメントの位置に応じてフラグメントの色が徐々に変化するのは当然であり、三角形は滑らかな色のグラデーション効果を示します。

さまざまな変数の役割と補間プロセス

これで、頂点シェーダーとフラグメント シェーダー間のジオメトリ アセンブリとラスタライズ プロセスを理解し、WebGL システムがフラグメントごとにフラグメント シェーダーを実行する方法を理解しました。

上記の色付き三角形プログラムに戻ると、このプログラムは、学習したばかりの知識を使用して、頂点シェーダーで各頂点の色のみを指定し、最終的にグラデーション カラー効果を持つ三角形を取得する理由を説明することもできます。実際、頂点の色を頂点シェーダーの可変変数 v_Color に割り当て、その値がフラグメント シェーダーの同じ名前と型の変数 (つまり、フラグメント シェーダーの可変変数 v_Color) に渡されます。 ). 以下に示すように。ただし、より正確に言うと、頂点シェーダーの v_Color 変数は、フラグメント シェーダーに渡される前に補間されます。したがって、フラグメント シェーダーの v_Color 変数と頂点シェーダーの v_Color 変数は実際には同じものではありません。そのため、このタイプの変数を「可変」変数と呼びます。

さまざまな変数の動作

さまざまな変数の補間

 より正確には、赤い三角形では、さまざまな変数で三角形の 3 つの異なる頂点に 3 つの異なる色を指定し、三角形の表面上のこれらのフラグメントの色の値が、WebGL システムで使用される色です。これら 3 つの頂点が補間されます。

たとえば、2 つの端点が異なる色である線分を考えてみましょう。一方のエンドポイントは赤色 (1.0、0.0、0.0) で表示され、もう一方のエンドポイントは青色 (0.0、0.0、1.0) で表示されます。これら 2 つの色 (赤と青) を頂点シェーダーの可変変数 v_Color に割り当てます。その後、WebGL が線分上のすべての点 (フラグメント) の色を自動的に計算し、それらをフラグメント シェーダーに割り当てます。可変変数 v_Color (以下の図に示すように)。

色の値の補間

この例では、RGBA の R 値が 1.0 から 0.0 に減少し、B 値が 0.0 から 1.0 に増加します。線分上のすべてのフラグメントのカラー値が適切に計算されます。このプロセスは補間補間プロセスと呼ばれますこの方法で 2 点間の各フラグメントの新しいカラーが計算されると、それらはフラグメント シェーダーの v_Color 変数に渡されます。 

赤い三角のプログラムコードを見てみましょう頂点シェーダーでは、三角形の 3 つの頂点の色を可変変数 v_Color (9 行目) に割り当て、フラグメント シェーダーの可変変数 v_Color は補間されたフラグメント カラーを受け取ります。フラグメント シェーダーでは、フラグメントの色を gl_FragColor 変数 (19 行目) に割り当て、色付きの三角形を描画します。同様に、さまざまな変数ごとにこのような補間プロセスが実行されます

要約する 

頂点シェーダーとフラグメントシェーダーの間のプロセスは非常に重要です。ラスタライズも 3 次元グラフィックスの重要なテクノロジの 1 つであり、ベクトル ジオメトリをラスタライズされたフラグメント (ピクセル) に変換する役割を果たします。グラフィックスがフラグメントに変換された後、各フラグメントに異なる色を割り当てるなど、フラグメント シェーダー内でさらに多くのことを行うことができます。色は補間したり、プログラムで指定したりできます。 

おすすめ

転載: blog.csdn.net/dabaooooq/article/details/132611118