WebGL テクスチャ - 長方形の表面に画像を貼り付けます

目次

WebGL でテクスチャ マッピングを実行するには、次の 4 つの手順に従う必要があります。 

1. ジオメトリにマッピングされたテクスチャ画像を準備します。

2. ジオメトリのテクスチャ マッピング方法を設定します。

3. テクスチャ イメージをロードし、WebGL で使用できるように少し設定します。

4. フラグメント シェーダのテクスチャから対応するテクセルを抽出し、そのテクセルの色をフラグメントに割り当てます。

テクスチャ座標

テクスチャ イメージをジオメトリに貼り付ける

サンプルコード

このプログラムは主に5つのパートに分かれています。

1. 頂点シェーダーは頂点のテクスチャ座標を受け取り、ラスタライズ後にフラグメント シェーダーに渡します。

2. フラグメント シェーダは、フラグメントのテクスチャ座標に基づいてテクスチャ イメージからテクセル カラーを抽出し、それを現在のフラグメントに割り当てます。

3. 頂点のテクスチャ座標を設定します (initVertexBuffers())。

4. ロードするテクスチャ画像を準備し、ブラウザにそれを読み取らせます (initTextures())。

5. テクスチャ イメージのロード イベントをリッスンし、ロードが完了したら、WebGL システムでテクスチャ (loadTexture()) を使用します。

テクスチャ座標の設定 (initVertexBuffers())

テクスチャの設定とロード (initTextures()) 

 gl.createTexture() メソッドの仕様。

gl.deleteTexture() メソッドの仕様

テクスチャ画像を非同期でロードする

WebGL 用のテクスチャの構成 (loadTexture()) 

画像のY軸反転

gl.pixelStorei()メソッド仕様

 テクスチャ ユニットをアクティブにする (gl.activeTexture())

 gl.activeTexture() メソッドの仕様

バインド テクスチャ オブジェクト (gl.bindTexture()) 

 gl.bindTexture() メソッドの仕様

テクスチャ オブジェクトのパラメータを設定します (gl.texParameteri())

gl.texParameteri()メソッド仕様

pname には 4 つのテクスチャ パラメータを指定できます。 

テクスチャパラメータとそのデフォルト値

gl.TEXTURE_MAG_FILTER および gl.TEXTURE_MIN_FILTER に割り当てることができる非ピラミッド テクスチャ タイプの定数。

gl.TEXTURE_WRAP_S および gl.TEXTURE_WRAP_T に割り当てられる定数

テクスチャ画像をテクスチャオブジェクトに割り当てる(gl.texImage2D())

gl.texImage2D()メソッド仕様

テクセルデータのフォーマット

テクスチャ ユニットをフラグメント シェーダに渡す (gl.uniform1i()) 

テクスチャに固有のデータ型

テクスチャ座標を頂点シェーダーからフラグメントシェーダーに転送します。 

フラグメント シェーダでテクスチャ ピクセル カラーを取得する (texture2D()) 

texture2D()メソッドの仕様

texture2D()メソッドの戻り値

演習: テクスチャ座標を変更してテクスチャ マッピング効果を変更する


問題は、下の写真のようなリアルなレンガ壁を作成したい場合に発生します。壁のポットホールをシミュレートするために、色と位置を指定して三角形を多数作成したくなるかもしれません。そうすると、退屈で無意味な苦しみの海にはまってしまうことになります。

3 次元グラフィックスには、この問題を解決できる非常に重要なテクノロジがあることはすでにご存じかもしれません。それがテクスチャマッピングです。テクスチャ マッピングは実際には非常に簡単で、幾何学的図形の表面に画像 (ステッカーのようなもの) をマッピング (貼り付け) するだけです。2 つの三角形で構成される長方形に現実世界の画像を貼り付け、長方形の表面が画像のように見えるようにします。このとき、この絵をテクスチャ画像またはテクスチャと呼ぶことできる

テクスチャ マッピングの機能は、以前にラスタライズされた各フラグメントをテクスチャ イメージに基づいて適切な色でペイントすることです。テクスチャ画像を構成するピクセルはテクセル(テクスチャ要素)とも呼ばれ、各テクセルの色は下図に示すように RGB または RGBA 形式でエンコードされます。

WebGL でテクスチャ マッピングを実行するには、次の 4 つの手順に従う必要があります。 

1. ジオメトリにマッピングされたテクスチャ画像を準備します。

2. ジオメトリのテクスチャ マッピング方法を設定します。

3. テクスチャ イメージをロードし、WebGL で使用できるように少し設定します。

4. フラグメント シェーダのテクスチャから対応するテクセルを抽出し、そのテクセルの色をフラグメントに割り当てます。

テクスチャ マッピングの仕組みをより深く理解するために、長方形の表面にテクスチャ イメージをアタッチするサンプル プログラムを作成してみましょう。ブラウザでコードを実行すると、結果は次のようになります。 

 

次に、上記のステップ 1 ~ 4 を詳しく見てみましょう。手順 1 で準備したテクスチャ画像は、ブラウザがサポートする任意の形式の画像にすることができます。どの写真でも使用できます

2 番目のステップは、マッピング方法を指定することです。これは、「ジオメトリの特定の断片」の色が「テクスチャ イメージ内のどの (またはいくつかの) ピクセル」にどのように依存するかを決定することです (つまり、前者のマッピング後者)。シェイプの頂点座標を使用して、画面のどの部分がテクスチャ イメージでカバーされるかを決定し、テクスチャ座標 (テクスチャ座標) を使用して、テクスチャ イメージのどの部分がジオメトリをカバーするかを決定します。テクスチャ座標は新しい座標系です。詳しく見てみましょう。

テクスチャ座標

テクスチャ座標はテクスチャ画像上の座標であり、テクスチャ画像上のテクセルカラーを取得することができます。WebGL システムのテクスチャ座標系は、次の図に示すように 2 次元です。テクスチャ座標を広く使用されている x 座標および y 座標と区別するために、WebGL では s および t (st/uv 座標系) を使用してテクスチャ座標に名前を付けます。

上図のように、テクスチャ画像の四隅の座標は、左下隅(0.0, 0.0)、右下隅(1.0, 0.0)、右上隅(1.0, 1.0)、上隅(1.0, 1.0)となります。左隅 (0.0、1.0)。テクスチャ座標は、座標値が画像自体のサイズとは関係がないため、非常に一般的です。128×128 または 128×256 の画像であっても、右上隅のテクスチャ座標は常に (1.0, 1.0) )。

テクスチャ イメージをジオメトリに貼り付ける

前述したように、WebGL では、下図に示すように、テクスチャ画像のテクスチャ座標と幾何学的形状の頂点座標のマッピング関係によって、テクスチャ画像の貼り付け方法を決定します。

ここでは、テクスチャ座標 (0.0, 1.0) を頂点座標 (-0.5, -0.5, 0.0) に、テクスチャ座標 (1.0, 1.0) を頂点座標 (0.5, 0.5, 0.0) にマッピングします。長方形の 4 つの頂点とテクスチャ座標の対応関係を確立すると、上図 (右) の結果が得られます。 

テクスチャ マッピングの原理については大体理解できたので、サンプル プログラムを見てみましょう。

サンプルコード

以下にサンプルプログラムを示します。テクスチャ マッピングのプロセスでは、頂点シェーダーとフラグメント シェーダーの両方の連携が必要です。まず、頂点シェーダーで各頂点のテクスチャ座標が指定され、次にフラグメント シェーダーで各フラグメントのテクスチャ座標がテクスチャ画像からテクセルカラーを抽出します。プログラムは主に 5 つの部分で構成されており、コード内でマークされています。

// 顶点着色器 (第一部分) p157
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec2 a_TexCoord;\n' +
  'varying vec2 v_TexCoord;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  v_TexCoord = a_TexCoord;\n' +
  '}\n';

// 片元着色器 (第二部分)
var FSHADER_SOURCE =
  '#ifdef GL_ES\n' +
  'precision mediump float;\n' +
  '#endif\n' +
  'uniform sampler2D u_Sampler;\n' +
  'varying vec2 v_TexCoord;\n' +
  'void main() {\n' +
  '  gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
  '}\n';

function main() {
  var canvas = document.getElementById('webgl');
  var gl = getWebGLContext(canvas);
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }
  // 设置顶点信息 (第三部分)
  var n = initVertexBuffers(gl);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  // 配置纹理
  if (!initTextures(gl, n)) {
    console.log('Failed to intialize the texture.');
    return;
  }
}

function initVertexBuffers(gl) {
  var verticesTexCoords = new Float32Array([
    // 顶点坐标, 纹理坐标
    -0.5,  0.5,   0.0, 1.0,
    -0.5, -0.5,   0.0, 0.0,
     0.5,  0.5,   1.0, 1.0,
     0.5, -0.5,   1.0, 0.0,
  ]);
  var n = 4; // 顶点数
  // 创建缓冲区对象
  var vertexTexCoordBuffer = gl.createBuffer();
  // 将顶点坐标和纹理坐标写入缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
  var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
  gl.enableVertexAttribArray(a_Position);  // 启用缓冲区对象的分配a_Position
  // 将纹理坐标分配给a_TexCoord并开启它
  var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
  gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
  gl.enableVertexAttribArray(a_TexCoord);  // 启用缓冲区对象的分配a_TexCoord
  return n;
}

// 第四部分
function initTextures(gl, n) {
  var texture = gl.createTexture();   // 创建纹理对象
  // 获取 u_Sampler 的存储位置
  var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
  var image = new Image(); 
  // 注册图像加载事件的响应函数
  image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); };
  // 浏览器开始加载图像
  image.src = '../resources/sky.jpg';
  return true;
}

// 第五部分
function loadTexture(gl, n, texture, u_Sampler, image) {
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 对纹理图像进行y轴反转
  // 开启0号纹理单元
  gl.activeTexture(gl.TEXTURE0);
  /* 
    向target绑定纹理对象:通过 gl.activeTexture 方法激活了纹理单元0。然后,纹理对象 texture 使用 gl.bindTexture 方法将其绑定到当前激活的纹理单元上 gl.TEXTURE0。
    在 WebGL 中,首先需要激活一个纹理单元并将纹理对象绑定到该纹理单元上,然后才能指定纹理目标的类型。
  */
  gl.bindTexture(gl.TEXTURE_2D, texture);
  // 配置纹理参数
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  // 配置纹理对象
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  // 将0号纹理传递给着色器
  gl.uniform1i(u_Sampler, 0);
  
  gl.clear(gl.COLOR_BUFFER_BIT);   // 清楚canvas
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // 绘制矩形
}

このプログラムは主に5つのパートに分かれています。

1. 頂点シェーダーは頂点のテクスチャ座標を受け取り、ラスタライズ後にフラグメント シェーダーに渡します。

2. フラグメント シェーダは、フラグメントのテクスチャ座標に基づいてテクスチャ イメージからテクセル カラーを抽出し、それを現在のフラグメントに割り当てます。

3. 頂点のテクスチャ座標を設定します (initVertexBuffers())。

4. ロードするテクスチャ画像を準備し、ブラウザにそれを読み取らせます (initTextures())。

5. テクスチャ イメージのロード イベントをリッスンし、ロードが完了したら、WebGL システムでテクスチャ (loadTexture()) を使用します。

 パート 3 (initVertexBuffers() を使用して各頂点のテクスチャ座標を設定) から始めましょう。シェーダー (最初の 2 つの部分) はイメージがロードされた後に実行されるため、最後に説明します。

テクスチャ座標の設定 (initVertexBuffers())

テクスチャ座標を頂点シェーダーに渡すことは、他の頂点データ (カラーなど) を頂点シェーダーに渡すことと同じです。テクスチャ座標と頂点座標を同じバッファに書き込むことができます。次のように、頂点座標と各頂点のテクスチャ座標をペアで記録する配列 verticesTexCoords を定義します (行 40)。

最初の頂点 (-0.5, 0.5) に対応するテクスチャ座標は (0.0, 1.0)、2 番目の頂点 (-0.5, -0.5) に対応するテクスチャ座標は (0.0, 0.0) であることがわかります。 3 番目の頂点に対応するテクスチャ座標 (0.5, 0.5) に対応するテクスチャ座標は (1.0, 1.0)、4 番目の頂点 (0.5, -0.5) に対応するテクスチャ座標は (1.0, 0.0) です。
次に、頂点座標とテクスチャ座標をバッファ オブジェクトに書き込み、頂点座標を a_Position 変数に代入してオンにします (51 ~ 56 行目)。次に、a_TexCoord変数の格納場所を取得し、バッファ内のテクスチャ座標を変数に代入し(58~59行目)、変数を開きます(60行目)。

テクスチャの設定とロード (initTextures()) 

initTextures() 関数は、テクスチャの構成とロード (行 66 ~ 73) を担当します。最初に gl.createTexture() を呼び出して、WebGL システムでテクスチャを管理するために使用されるテクスチャ オブジェクトを作成します (行 63)。次に、gl.getUniformLocation() を呼び出して、テクスチャ イメージを受け取るために使用されるフラグメント シェーダからユニフォーム変数 u_Sampler (サンプラー) の格納場所を取得します (行 68)。

 gl.createTexture() メソッドの仕様。

 この関数を呼び出すと、次の図に示すように、WebGL システムにテクスチャ オブジェクトが作成されます。gl.TEXTURE0~gl.TEXTURE7は、テクスチャ画像を管理する8つのテクスチャユニット(詳細は後述)であり、それぞれテクスチャをバインドする際のテクスチャ対象となるgl.TEXTURE_2Dと関連付けられている。これらについては後で詳しく説明します。

同様に、 gl.deleteTexture() を使用してテクスチャ オブジェクトを削除できます。すでに削除されているテクスチャ オブジェクトを削除しようとしても、エラーは報告されず、影響はないことに注意してください。

gl.deleteTexture() メソッドの仕様

 

次に、ブラウザは、WebGL で使用するテクスチャ イメージをロードするように求められます。テクスチャ イメージは四角形にマッピングされます。これを行うには、Image オブジェクトを使用する必要があります。

 

このコードは、Image オブジェクトを作成し、それに対して onload イベント応答関数loadTexture() を登録します。この関数は、イメージがロードされた後に呼び出されます。最後に、ブラウザーに画像のロードを開始するように通知されます。

新しい Image オブジェクトを作成するには、新しい Array オブジェクトまたは Date オブジェクトを作成するとき (114 行目) と同様に、new 演算子を使用する必要があります。画像は JavaScript に組み込まれたオブジェクト タイプで、通常は画像を処理するために使用されます。

 

画像の読み込みプロセスは非同期であるため (詳しくは後述します)、読み込み完了イベント (onload イベント) をリッスンする必要があります。ブラウザが画像の読み込みを完了すると、読み込まれた画像が WebGL システムに渡されます。onload イベント応答関数を登録することは、テクスチャ イメージのロードが完了した後にブラウザに非同期でloadTexture() 関数を呼び出すように指示することと同じです (行 71)。 

 

loadTexture() 関数は 5 つのパラメータを受け取り、最後のパラメータはロードされたばかりの画像 (つまり、Image オブジェクト) です。最初のパラメータ gl は WebGL 描画コンテキスト、パラメータ n は頂点の数、パラメータ texture は以前に作成されたテクスチャ オブジェクト (行 66)、u_Sampler はシェーダ内の均一変数 u_Sampler の格納場所です。 

HTML の <img> タグと同じように、Image オブジェクトに src 属性を追加し、その属性を画像ファイルのパスと名前に割り当てて、ブラウザに画像のロードを開始するように指示します (73 行目)。セキュリティ上の理由から、WebGL ではクロスドメイン テクスチャ イメージの使用が許可されていないことに注意してください。

73 行目の実行後、ブラウザは画像の非同期ロードを開始しますが、プログラム自体は (画像のロードが完了するのを待たずに) 74 行目の return ステートメントに進み、終了します。その後、ブラウザがある時点で画像のロードが完了すると、イベント応答関数loadTexture()を呼び出して、ロードされた画像を処理のためにWebGLシステムに渡します。

テクスチャ画像を非同期でロードする

WebGLはブラウザ上で動作するため、ディスクから直接画像を読み取ることはできず、ブラウザを介して間接的に画像を取得することしかできません。(通常、ブラウザはサーバーへのリクエストを開始し、サーバーの応答を受信し、サーバーから画像を取得します。) この利点は、ブラウザがサポートする任意の形式の画像を使用できることですが、欠点は、 image プロセスがより複雑になりました。画像を取得するには、2 つのステップ (ブラウザー要求、および実際に WebGL システムに画像をロードする) を実行する必要があります。これらの 2 つのステップは非同期 (バックグラウンド) で実行され、現在のプログラムの実行はブロックされません。

以下の図は、サンプルプログラムの手順[1](ブラウザに画像の読み込みを通知)から手順[7](画像読み込み後のloadTexture()の呼び出し)までの処理を示しています。

上図ではステップ[1]、[2]が順番に実行されていますが、ステップ[2]から[7]は順番に実行されません。ステップ [2] では、ブラウザーに画像のロードを要求した後、JavaScript プログラムは停止せず、画像がロードされるまで待機せず、前方に実行を続けました。(この動作の仕組みについては後で詳しく説明します。) JavaScript が実行され続けている間、ブラウザは Web サーバーに画像のロードを要求します [3]。次に、ブラウザが画像 [4] と [5] のロードを完了すると、画像がロードされたことを JavaScript プログラムに通知します。このプロセスは非同期と呼ばれます。上の画像の非同期読み込みプロセスは、HTML Web ページに画像を表示するプロセスと非常によく似ています。HTML Web ページでは、<img> タグの src 属性に画像ファイルの URL を指定することで、画像をロードする指定 URL をブラウザに伝えます (以下を参照)。このプロセスは、実際には図 5.23 のステップ [2] です。

画像が満載の Web ページのパフォーマンスを考えてみてください。ブラウザによる画像の読み込みは本質的に非同期プロセスです。一般的に、これらの Web ページのレイアウトとテキストはすぐに表示され、その後、画像が読み込まれるにつれて徐々に画像が表示されます。画像の読み込みと表示のプロセスが非同期であるため、すべての画像が読み込まれるのを待つことなく、Web ページを開いたらすぐに Web ページ上のテキストを表示して操作することができます。

WebGL 用のテクスチャの構成 (loadTexture()) 

loadTexture() 関数は次のように定義されます。

この関数の主なタスクは、WebGL で使用できるようにテクスチャを構成することです。テクスチャ オブジェクトの使用はバッファの使用と非常に似ているので、見てみましょう。 

画像のY軸反転

画像を使用する前に、Y 方向に反転する必要があります。

このメソッドは、画像の Y 軸反転を実行します。以下の図に示すように、WebGL テクスチャ座標系の t 軸の方向は、PNG、BMP、JPG などの形式の画像の座標系の Y 軸の方向と逆になります。したがって、画像の Y 軸を反転することによってのみ、画像をグラフに正しくマッピングできます。(あるいは、シェーダー内の t 軸座標を手動で反転することもできます。) 

gl.pixelStorei()メソッド仕様

 テクスチャ ユニットをアクティブにする (gl.activeTexture())

WebGL では、テクスチャ ユニットと呼ばれる仕組みにより、複数のテクスチャを同時に使用します。各テクスチャユニットには、テクスチャ画像を管理するユニット番号が付与されている。プログラムでテクスチャ イメージのみを使用する必要がある場合でも、テクスチャ ユニットを指定する必要があります。

システムでサポートされるテクスチャ ユニットの数は、ハードウェアとブラウザの WebGL 実装によって異なりますが、デフォルトでは、WebGL は少なくとも 8 つのテクスチャ ユニットをサポートし、他のシステムによってはそれ以上のテクスチャ ユニットがサポートされます。組み込み変数 gl.TEXTRUE0、gl.TEXTURE1...gl.TEXTURE7 はそれぞれテクスチャ ユニットを表します。

テクスチャ ユニットを使用する前に、次の図に示すように、 gl.activeTexture() を呼び出してアクティブにする必要もあります。 

 gl.activeTexture() メソッドの仕様

 

バインド テクスチャ オブジェクト (gl.bindTexture()) 

次に、テクスチャ オブジェクトが使用しているテクスチャのタイプを WebGL システムに伝える必要があります。テクスチャ オブジェクトを操作する前に、テクスチャ オブジェクトをバインドする必要があります。これはバッファとよく似ています。バッファ オブジェクトを操作する (データの書き込みなど) 前に、バッファ オブジェクトもバインドする必要があります。WebGL では、以下に示す 2 種類のテクスチャがサポートされています。

プログラム例では2次元画像をテクスチャとして使用しているため、gl.TEXTURE_2Dを渡しています(86行目)。

テクスチャ オブジェクトをテクスチャ ユニットおよびテクスチャ ターゲットにバインドする

 gl.bindTexture() メソッドの仕様

 

このメソッドは、テクスチャ オブジェクトを開くことと、テクスチャ オブジェクトをテクスチャ ユニットにバインドするという 2 つのタスクを完了することに注意してください。(最初にテクスチャ オブジェクトをテクスチャ ユニットにバインドする必要があります。その後、テクスチャ ターゲット タイプを指定してバインドできます。)この例では、テクスチャ ユニット 0 (gl.TEXTURE0) がアクティブ化されているため、86 行目を実行した後、の場合、WebGL システムの内部状態は次の図のようになります。 

このようにして、テクスチャ オブジェクトの種類 (gl.TEXTURE_2D) を指定します。実はWebGLではテクスチャオブジェクトを直接操作することはできず、テクスチャオブジェクトをテクスチャユニットにバインドし、テクスチャユニットを操作することでテクスチャオブジェクトを操作する必要があります。 

テクスチャ オブジェクトのパラメータを設定します (gl.texParameteri())

次に、テクスチャ オブジェクトのパラメータを構成して、テクスチャ イメージをグラフィックスにマッピングする具体的な方法、つまりテクスチャ座標に基づいてテクセル カラーを取得する方法、およびテクスチャを繰り返し塗りつぶす方法を設定する必要があります。これらのパラメータを設定するには、一般関数 gl.texParameteri() を使用します。

gl.texParameteri()メソッド仕様

pname には 4 つのテクスチャ パラメータを指定できます。 
  • 増幅方法(gl.TEXTURE_MAG_FILTER) : テクスチャの描画範囲がテクスチャそのものより大きい場合のテクセルカラーの取得方法を指定します。たとえば、16×16 のテクスチャ イメージを 32×32 ピクセル空間にマッピングすると、テクスチャ サイズは元のサイズの 2 倍になります。WebGL は拡大によって生じるピクセル間のギャップを埋める必要があり、このパラメーターはこれらのギャップを埋める具体的な方法を示します。

  • 縮小方法(gl.TEXTURE_MIN_FILTER) : このパラメータは、テクスチャの描画範囲がテクスチャ自体よりも小さい場合のテクセルカラーの取得方法を示します。たとえば、32×32 のテクスチャ イメージを 16×16 ピクセルの空間にマッピングすると、テクスチャは元のサイズの半分になります。WebGL ではテクスチャを軽減するためにテクスチャ画像内のピクセルを削除する必要がありますが、このパラメータはピクセルを削除する具体的な方法を示します。
  • 水平方向の塗りつぶし方法 (gl.TEXTURE_WRAP_S) : このパラメータは、テクスチャ画像の左側または右側の領域を塗りつぶす方法を示します。
  • 垂直塗りつぶし方法 (gl.TEXTURE_WRAP_T) : このパラメータは、テクスチャ画像の上下の領域を塗りつぶす方法を示します。

以下の表 5.3 に、各テクスチャ パラメータのデフォルト値を示します。

テクスチャパラメータとそのデフォルト値


以下の表 5.4 は、 gl.TEXTURE_MAG_FILTER および gl.TEXTURE_MIN_FILTER に割り当てることができる定数を示しています。

gl.TEXTURE_MAG_FILTER および gl.TEXTURE_MIN_FILTER に割り当てることができる非ピラミッド テクスチャ タイプの定数。

 

マンハッタン距離は長方形距離、チェッカーボード距離です。たとえば、(x1, y1) と (x2, y2) の間のマンハッタン距離は |x1-x2|+|y1-y2| です。

以下の表 5.5 に、 gl.TEXTURE_WRAP_S および gl.TEXTURE_WRAP_T に割り当てることができる定数を示します。

gl.TEXTURE_WRAP_S および gl.TEXTURE_WRAP_T に割り当てられる定数

表 5.3に示すように各テクスチャ パラメータにはデフォルト値があり、通常は gl.texParameteri() を呼び出さずにデフォルト値を使用できます。ただし、この例では gl.TEXTURE_MIN_FILTER パラメータを変更します。このパラメータのデフォルト値は MIPMAP (ピラミッドとも呼ばれる) と呼ばれる特殊なテクスチャ タイプです。MIPMAP テクスチャは、実際には一連のテクスチャ、または元のテクスチャ イメージの一連の異なる解像度バージョンです。要約すると、パラメータ gl.TEXTURE_MIN_FILTER を gl.LINEAR に設定します (88 行目)。 

テクスチャ オブジェクトのパラメータを設定した後の WebGL システムの内部状態は、次の図に示されています。

 次に、テクスチャ イメージをテクスチャ オブジェクトに割り当てます。

テクスチャ画像をテクスチャオブジェクトに割り当てる(gl.texImage2D())

gl.texImage2D() メソッドを使用してテクスチャ イメージをテクスチャ オブジェクトに割り当てます。これにより、WebGL システムにイメージに関するいくつかのプロパティを伝えることもできます。

gl.texImage2D()メソッド仕様

このメソッドはサンプル プログラムの 90 行目で呼び出しています。 

このとき、下図に示すように、Image オブジェクト内の画像が JavaScript から WebGL システムに渡され、テクスチャ オブジェクトに格納されます。

テクスチャオブジェクトに画像を割り当てる

 

 このメソッドを呼び出すときの各パラメータの値を簡単に見てみましょう。ピラミッド テクスチャを使用しないため、level パラメーターには 0 を使用します。formatパラメータはテクスチャデータのフォーマットを示し、具体的な値は下表の通りであり、テクスチャ画像のフォーマットに応じて選択する必要があります。サンプルプログラムで使用するテクスチャ画像はJPG形式であり、各ピクセルをRGBの3成分で表現するため、パラメータをgl.RGBと指定します。PNG 形式の画像など、他の形式の画像の場合は通常 gl.RGBA が使用され、BMP 形式の画像には通常 gl.RGB が使用され、グレースケール画像には通常 gl.LUMINANCE および gl.LUMINANCE_ALPHA が使用されます。

テクセルデータのフォーマット

ここでのルーメンは、物体の表面で知覚される明るさを表します。ルーメンは通常、物体の表面の赤、緑、青の色成分値の加重平均を使用して計算されます。

gl.texImage2D() メソッドは、WebGL システムのテクスチャ オブジェクトにテクスチャ イメージを保存します。保存したら、internalformat パラメータを介してテクスチャ イメージの形式タイプをシステムに伝える必要がありますWebGL では、internalformat は format と同じである必要があります

typeパラメータはテクスチャ データ タイプを指定します。以下の表を参照してください。通常、gl.UNSIGNED_BYTE データ型を使用します。もちろん、gl.UNSIGNED_SHORT_5_6_5 (RGB 3 つのコンポーネントを 16 ビットに圧縮) など、他のデータ型も使用できます。後者のデータ形式は、ブラウザが画像を読み込むのにかかる時間を短縮するためにデータを圧縮するためによく使用されます。

テクスチャデータのデータ形式

テクスチャ ユニットをフラグメント シェーダに渡す (gl.uniform1i()) 

テクスチャ イメージが WebGL システムに渡されたら、フラグメント シェーダに渡してグラフィックスの表面にマッピングする必要があります。前に述べたように、テクスチャ イメージはフラグメントによって変化しないため、テクスチャを表すためにユニフォーム変数を使用します。

シェーダー内のテクスチャ オブジェクトを表すユニフォーム変数は、次の表に示すように、テクスチャ オブジェクト専用の特別なデータ型として宣言する必要があります。サンプルプログラムでは2次元テクスチャgl.TEXTURE_2Dを使用しているため、uniform変数のデータ型はsampler2Dとなります。 

テクスチャに固有のデータ型

initTextures() 関数 (78 行目) では、ユニフォーム変数 u_Sampler (108 行目) のストレージ アドレスを取得し、それをパラメータとしてloadTexture() 関数に渡します。テクスチャ ユニット番号(gl.TEXTUREn の n)を指定して、テクスチャ オブジェクトを u_Sampler に渡す必要があります。この例の唯一のテクスチャ オブジェクトは gl.TEXTURE0 にバインドされているため、gl.uniformi() を呼び出すときの 2 番目のパラメーターは 0 になります。 

92 行目を実行すると、WebGL システムの内部状態が以下に示され、フラグメント シェーダが最終的にテクスチャ イメージにアクセスできるようになります。

テクスチャ座標を頂点シェーダーからフラグメントシェーダーに転送します。 

属性変数 a_TexCoord を通じて頂点のテクスチャ座標を受け取るため、データを可変変数 v_TexCoord に割り当て、テクスチャ座標をフラグメント シェーダに渡すことが可能です。フラグメント シェーダーと頂点シェーダー内の同じ名前とタイプのさまざまな変数を使用して、2 つのシェーダー間でデータを転送できることを覚えているかもしれません。頂点間のフラグメントのテクスチャ座標はラスタライズ プロセス中に補間されるため、フラグメント シェーダーでは補間されたテクスチャ座標を使用します。

これで、WebGL システムでテクスチャを使用するための準備がすべて完了しました。

残りの作業は、フラグメントのテクスチャ座標に従ってテクスチャ イメージからテクセルの色を抽出し、それを現在のフラグメントに適用することです。

フラグメント シェーダでテクスチャ ピクセル カラーを取得する (texture2D()) 

フラグメント シェーダはテクスチャ イメージからテクセルの色を取得します (19 行目)。

GLSL ES 組み込み関数 texture2D() を使用して、テクセル カラーを抽出しますこの関数の使い方は簡単で、テクスチャ ユニット番号とテクスチャ座標の 2 つのパラメータを渡すだけで、テクスチャ上のピクセル カラーを取得できます。この関数は組み込みです。パラメータの型と戻り値に注意してください。 

texture2D()メソッドの仕様

texture2D()メソッドの戻り値

 

テクスチャのアップスケーリング メソッドとダウンスケーリング メソッドのパラメータによって、WebGL システムがフラグメントを補間する方法が決まりますtexture2D() 関数の戻り値を gl_FragColor 変数に割り当て、フラグメント シェーダが現在のフラグメントをこの色に染めます。最後に、テクスチャ イメージがシェイプ (この場合は長方形) にマッピングされ、最終的に描画されます。 

これはテクスチャ マッピングの最終ステップです。この時点で、テクスチャはロード、セットアップ、グラフィックへのマッピングが完了し、描画するのを待つだけになります。

ご覧のとおり、WebGL でのテクスチャ マッピングは比較的複雑なプロセスです。その理由の 1 つは、ブラウザにテクスチャ イメージを読み込ませる必要があることと、テクスチャが 1 つしかない場合でもテクスチャ ユニットを使用する必要があるためです。

演習: テクスチャ座標を変更してテクスチャ マッピング効果を変更する

テクスチャ マッピングにさらに慣れるために、サンプル プログラムのテクスチャ座標を変更してみましょう。たとえば、この例のテクスチャ座標を次のように変更します。

変更したプログラム コードの実行結果を次の図 (左) に示します。右の図は、長方形の 4 つの頂点のテクスチャ座標と、長方形上のテクスチャ画像の四隅の位置を示しており、テクスチャ座標系を理解するのに役立ちます。 

テクスチャ イメージは四角形全体をカバーできるほど大きくないため、空であるはずの領域でテクスチャが繰り返されていることがわかります。その理由は、サンプル プログラムでは、gl.TEXTURE_WRAP_S パラメーターと gl.TEXTURE_WRAP_T パラメーターの両方を gl.REPEAT に設定しているためです。 

次に、テクスチャ パラメータを次のように変更して、他にどのような効果が得られるかを見てみましょう。変更されたプログラムは TexturedQuad_Clamp_Mirror と呼ばれ、下の図はブラウザーでどのように実行されるかを示しています。

s 軸 (横軸) では、テクスチャが最もエッジのテクセルの色で塗りつぶされ、t 軸 (縦軸) では、テクスチャが鏡像で繰り返し塗りつぶされていることがわかります。 

おすすめ

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