マルチテクスチャ
複数のテクスチャを使う
イメージを合成する
この方法を習得すれば、
一枚のポリゴンに対して複数のテクスチャを適用することが可能になります
複数のテクスチャをレンダリングするためには、何が必要だろうか?
マルチテクスチャでこれが大事になる
今回のサンプルでは、以下の二つの画像データを使います。
https://gyazo.com/12e27a2865a3c3b98ece56c42eafda31
シェーダ側に変更を加える
今回はまず、シェーダから修正してみましょう。
シェーダ側では複数のテクスチャユニットを受け取れるように uniform 変数を追加しなければなりません。
ただし、今回はポリゴンのテクスチャ座標は一枚目のテクスチャでも二枚目のテクスチャでも同じものを使いますので、
変更を加えるべきはフラグメントシェーダのみということになります。
フラグメントシェーダのソースを修正
code:frag
precision mediump float;
uniform sampler2D texture0;
uniform sampler2D texture1;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void){
vec4 smpColor0 = texture2D(texture0, vTextureCoord);
vec4 smpColor1 = texture2D(texture1, vTextureCoord);
gl_FragColor = vColor * smpColor0 * smpColor1;
}
uniform sampler2Dが増えた
テクスチャからフラグメントの情報を抜き出し、
頂点色と二つのテクスチャカラーを使って最終的に出力される色を算出する
javascript の修正
送るuniform変数を増やす
まずは定石どおり、uniformLocation の取得から。
uniformLocation を取得している部分を抜粋
code:js
// uniformLocationを配列に取得
var uniLocation = new Array();
uniLocation0 = gl.getUniformLocation(prg, 'mvpMatrix'); uniLocation1 = gl.getUniformLocation(prg, 'texture0'); uniLocation2 = gl.getUniformLocation(prg, 'texture1'); これは簡単ですね。純粋にシェーダから uniformLocation を取得しているだけです。
次に、テクスチャオブジェクトを準備します。これには、自作関数の create_texture を使っています。
テクスチャオブジェクトを生成する部分を抜粋
code:js
// テクスチャ用変数の宣言と生成
var texture0 = null, texture1 = null;
create_texture('texture0.png', 0);
create_texture('texture1.png', 1);
今回は複数のテクスチャを使うことになるため、ここで呼び出されている自作関数 create_texture を修正して、テクスチャのユニット番号を受け取るようにしています。
create_texture 関数
code:js
function create_texture(source, number){
// イメージオブジェクトの生成
var img = new Image();
// データのオンロードをトリガーにする
img.onload = function(){
// テクスチャオブジェクトの生成
var tex = gl.createTexture();
// テクスチャをバインドする
gl.bindTexture(gl.TEXTURE_2D, tex);
// テクスチャへイメージを適用
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
// ミップマップを生成
gl.generateMipmap(gl.TEXTURE_2D);
// テクスチャのバインドを無効化
gl.bindTexture(gl.TEXTURE_2D, null);
// 生成したテクスチャを変数に代入
switch(number){
case 0:
texture0 = tex;
break;
case 1:
texture1 = tex;
break;
default:
break;
}
};
// イメージオブジェクトのソースを指定
img.src = source;
}
第二引数に受け取ったテクスチャのユニット番号に応じて、最終的に生成されたテクスチャオブジェクトの代入先を変えています。それ以外は、前回のサンプルと何も変わっていません。
さて、あとは恒常ループ内で行なうシェーダへのテクスチャの登録処理だけです。
恒常ループ内の処理を抜粋
code:js
// テクスチャユニットを指定してバインドし登録する
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture0);
gl.uniform1i(uniLocation1, 0); // テクスチャユニットを指定してバインドし登録する
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i(uniLocation2, 1); ここでポイントとなるのは、テクスチャユニットの有効化と、テクスチャオブジェクトのバインド、そしてシェーダへのユニット番号の登録が全てワンセットになっていることです。
あとは通常どおり、座標変換行列などを適用しながら描画すれば、ポリゴンに二つのテクスチャが合成された状態でマッピングされます。意外と簡単だなぁという印象ではないでしょうか。
まとめ
マルチテクスチャレンダリングで注意するべきことは、正しくテクスチャユニットを指定しながらデータを処理すること、これに尽きます。
ちょっと紛らわしいかもしれませんが、要は activeTexture メソッドと uniform1i メソッドの使い方さえ間違えなければ、あとはシェーダ側で好きなようにテクスチャデータを利用できます。
今回は単純にシェーダ内で二つのテクスチャデータを乗算しているだけですが、個々のテクスチャデータに異なる処理を施すだけで、まったく別のレンダリング結果を生み出すことも可能です。固定機能パイプラインではなく、GLSL によるプログラマブルシェーダを使わざるを得ない実装になっているからこその醍醐味でもありますね。
サンプルへのリンクはいつものように下記にあります。
次回はテクスチャパラメータについて詳しく説明するつもりです。