物体表面にテクスチャを貼る手順について説明します。
テクスチャ上の位置は テクスチャ座標 (s,t)で表し、元の画像の大きさとは関係なく 0 ≤ s ≤ 1, 0 ≤ t ≤ 1 です。 テクスチャ座標系と、画像イメージの座標系ではy軸が反転していることに注意が必要です。
t ^ (0,1)| | | (0,0)+--------> s (1,0) |
(1,0) (0,0)+--------> x | | | (0,1)v |
テクスチャ座標系 | 画像データの座標系 |
WebGL や OpenGL/ES でテクスチャとして使用できる画像には次のような制約があります。
下のプログラムで利用しているのは1024x1024のjpegファイルです。
sakura1024.jpg |
一つのポリゴンを構成する各頂点に対して、その頂点がテクスチャ座標系で どこにあるかを与えておきます。この値をattribute変数で頂点シェーダに渡し、 頂点シェーダからvarying変数を経由してフラグメントシェーダに 渡すことで、各フラグメントごとのテクスチャ座標が補間によって求められて フラグメントシェーダに渡されます。
// v6----- v5 // /| /| // v1------v0| // | | | | // | |v7---|-|v4 // |/ |/ // v2------v3 tsuda.cube = {}; tsuda.cube.vertices = new Float32Array([ // x, y, z 1.0, 1.0, 1.0, // 0 v0 :front -1.0, 1.0, 1.0, // 1 v1 -1.0, -1.0, 1.0, // 2 v2 1.0, -1.0, 1.0, // 3 v3 ...(略) tsuda.cube.texCoord = new Float32Array([ 1.0, 1.0, // v0 :front 0.0, 1.0, // v1 0.0, 0.0, // v2 1.0, 0.0, // v3 ...(略)
WebGLではテクスチャ用の画像はネットワーク経由でブラウザに非同期的に読み込まれます。 画像データにアクセスできるのは読み込みが全て終了した後である点に注意しましょう。
画像の読み込みと、その後の処理はjavascriptで以下のように記述します。
var image = new Image();
image.onload = function() { 画像が読み込まれた後で実行すべき関数呼び出し; };画像の読み込みが終わると Image オブジェクトの onload プロパティに設定された イベントハンドラ(関数)が引数なしで呼び出されます。
image.src="画像へのパス";Imageオブジェクトの src プロパティに読み込みたい画像のパス(文字列)を設定すると、 ブラウザは画像の読み込みを開始します。 HTMLで<img>タグの要素のsrcプロパティで読み込む画像を設定したときの ブラウザの動作と似ています。
WebGLではテクスチャ画像をテクスチャユニットで管理します。 テクスチャユニットは少なくとも gl.TEXTURE0〜gl.TEXTURE7の8個が存在し、 同じ数だけ用意されたそれぞれの gl.TEXTURE_2D と対応しています。 テクスチャユニットに画像データを設定し、それをフラグメント シェーダに伝える手順を説明します。
WebGLでは複数のテクスチャを利用できます。 それぞれのテクスチャを管理するためにはテクスチャユニットを使います。 テクスチャユニットは少なくとも8個 (gl.TEXTURE0, gl.TEXTURE2, ..., gl.TEXTURE7)存在し、 それぞれに対応する TEXTURE_2D ユニットがあります。
テクスチャユニットのターゲットには gl.TEXTURE_2D と gl.TEXTURE_CUBE_MAP があります。 2次元画像を用いる場合は gl.TEXTURE_2Dをターゲットに指定します。
テクスチャの拡大・縮小方法や、繰り返し方についての設定をします。
javascriptのImageオブジェクト内の画像データを、WebGLの テクスチャオブジェクトへと転送します。
フラグメントシェーダに、使用するテクスチャを保持しているテクスチャユニット番号を uniform変数を用いて渡します。1個の整数を渡すにはgl.uniform1i()を用います。
頂点シェーダでは、頂点のテクスチャ座標系での位置がattribute変数で 渡されてくるので、varying変数に代入してフラグメントシェーダに渡します。
頂点シェーダ用プログラム |
attribute vec4 a_Position; attribute vec2 a_TexCoord; varying vec2 v_TexCoord; ... v_TexCoord = a_TexCoord; |
フラグメントシェーダで画像からテクセルの色を取り出し、対応するフラグメントに設定します。
テクスチャ画像を保持しているテクスチャユニットの番号はuniform変数で渡されています。 また、テクスチャ座標系でのフラグメントの位置は、補間された値がvarying変数で渡されています。
フラグメントシェーダ用プログラム | uniform sampler2D u_Sampler; varying vec2 v_TexCoord; ... vec4型の変数 = texture2D(u_Sampler,v_TexCoord); |
フラグメントシェーダの関数 | |||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
vec4 texture2D(sampler2D, vec2) @param sampler2d テクスチャユニット番号 @param vec2 テクスチャ座標の値 @return vec4 テクセルの色。画像が用意されていない場合は(0.0,0.0,0.0,1.0)。 | |||||||||||||||||||||||||||||||||||||||
glの関数 | |||||||||||||||||||||||||||||||||||||||
createTexture() テクスチャ画像を管理するテクスチャオブジェクトを生成する。 @return 作成されたテクスチャオブジェクト or null(エラーの場合) | |||||||||||||||||||||||||||||||||||||||
activeTexture(texUnit ) 指定したテクスチャユニット texUnit を有効にする。 @param texUnit : 有効にするテクスチャユニット。gl.TEXTURE[0-7] @return なし | |||||||||||||||||||||||||||||||||||||||
bindTexture(target , texture ) 有効になっているテクスチャユニットに対応するtarget に、テクスチャオブジェクトをバインドする。 @param target gl.TEXTURE_2D(2次元) or gl.TEXTURE_CUBE_MAP(3次元) @param texture テクスチャオブジェクト @return なし | |||||||||||||||||||||||||||||||||||||||
texParameteri(target , pname , param ) 有効になっているテクスチャユニットに対応するtarget の、pname パラメータ値を param に設定する。 @param target gl.TEXTURE_2D(2次元) or gl.TEXTURE_CUBE_MAP(3次元) @param pname テクスチャパラメータ名 @param param テクスチャパラメータの値 @return なし
| |||||||||||||||||||||||||||||||||||||||
texImage2D(target , level , internalformat , format , type , image ) 有効になっているテクスチャユニットに対応するtarget にバインドされたテクスチャオブジェクトに、 javascriptの image オブジェクトの画像を転送する。 @param target gl.TEXTURE_2D(2次元) or gl.TEXTURE_CUBE_MAP(3次元) @param level テクスチャがミップマップの場合はそのレベルを、それ以外の場合は0を指定する @param internalformat テクスチャ画像の内部フォーマット。 @param format テクセルのフォーマット。internalformat と同じ値。 @param type テクセルのデータ型 @param image Imageオブジェクト @return なし
|
ParaeelLightCube6.htmlが平行光線の元でひとつの立体を扱う最後のプログラムでした。 ParallelLightCube6.html から最小限の変更で物体表面にテクスチャを貼りつけてみます。 ここではシェーディングを考慮していません。
シェーディングを考慮したプログラムに変更しましょう。 頂点シェーダで計算したdiffuse成分とambient成分 の和が輝度(明るさ)となりますので、 この値をフラグメントシェーダに渡し、 フラグメントシェーダではテクセルの値に輝度を乗算してそのピクセルの色を決定します。
以下のプログラムでは、 ポリゴンの色は必要ないので、javascriptからWebGLに渡すのを止めています。 また、頂点シェーダ内で 「光の向きと面の法線から求めたデフューズ成分」と 「環境光からのくるアンビェント成分」を加算して輝度 (v_Brightness) としてフラグメントシェーダに渡しています。 フラグメントシェーダ内では、テクスチャからの色に輝度をそれぞれ 乗算して色を計算します。