[WebGL入門]二十七,多紋理
注:文章譯自http://wgld.org/,原作者杉本雅広(doxas),文章中如果有我的額外說明,我會加上[lufy:],另外,鄙人webgl研究還不夠深入,一些專業詞語,如果翻譯有誤,歡迎大家指正。
使用多個紋理
上次介紹了WebGL中的紋理的使用方法。簡單的實現了將紋理貼到四邊形中,果然是使用圖片資料的話比較靈活吧。那麼,這次來說說使用多個紋理來合成影象的方法,學習了這個方法之後可以再一個多邊形中使用多個紋理。
為了同時使用多個紋理,先來想想一下需要做些什麼呢?
上次已經簡單的基礎了,WebGL中管理紋理的方法是紋理單位,靈活使用這個紋理單位的話,就能實現多紋理的渲染了。
這次的demo使用下面兩個圖片。
>第一張
>第二張
下面就使用這兩張圖片來實現多紋理渲染。
著色器的修改
首先來看一下著色器的修改吧。為了渲染多紋理,著色器一側需要準備多個uniform變數,用來接收多個紋理單位,但是,這次多邊形的紋理座標只需要一個,無論第一個紋理還是第二個紋理都一樣,需要變更的程式碼如下。
>片段著色器的程式碼修改
如上,接收紋理情報的sampler2D型uniform變數一共有兩個,所做的處理和之前類似或者說一樣。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; }
使用GLSL的內建函式texture2D來獲取紋理的情報,使用頂點顏色和兩個紋理顏色計算出最終的輸出的顏色。
這次只需要修改片段著色器,頂點著色器沒有做任何改動。
javascript的修改
接著是javascript的程式碼修改,在這裡需要向新追加的uniform變數中傳入正確的紋理資料。
首先,固定的,uniformLocation的獲取。
>uniformLocation的獲取部分
這裡很簡單,純粹的從著色器中獲取uniformLocation。// uniformLocationを配列に取得 var uniLocation = new Array(); uniLocation[0] = gl.getUniformLocation(prg, 'mvpMatrix'); uniLocation[1] = gl.getUniformLocation(prg, 'texture0'); uniLocation[2] = gl.getUniformLocation(prg, 'texture1');
接著,準備紋理物件,這個還是使用自制的create_texture函式。
>紋理物件的生成部分
// テクスチャ用変數の宣言と生成
var texture0 = null, texture1 = null;
create_texture('texture0.png', 0);
create_texture('texture1.png', 1);
為了使用多個紋理,需要修改一下create_texture函式,來接收紋理單位的編號。>create_texture函式
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;
第二個引數用來接收紋理單位的編號,來確定生成的紋理物件要賦值給誰。其他地方和之前一樣,沒有變化。那麼,持續迴圈部分的地方要新增向著色器中新增紋理的處理。
>持續迴圈中的處理
// テクスチャユニットを指定してバインドし登録する
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture0);
gl.uniform1i(uniLocation[1], 0);
// テクスチャユニットを指定してバインドし登録する
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i(uniLocation[2], 1);
這裡的重點是,紋理單位的有效化,紋理物件的繫結,以及向著色器中設定單位編號是一個組合。另外,activeTexture函式中指定的紋理單位的編號和uniform1i函式的第二個引數中指定的整數值必須是一致的。其他的沒有變化,使用合適的座標變換矩陣的話,就能夠在多邊形中繪製合成狀態的紋理了,是不是出奇的簡單啊?
總結
多紋理進行渲染的時候應該注意的是,指定正確的紋理單位進行資料的處理,這就足夠了。
其他的細節,主要是activeTexture函式和uniform1i函式的使用方法,這幾個不出錯的話,之後就可以在著色器一側使用自己喜歡的圖片了。
這次只是單純的在著色器中將兩個紋理資料進行相乘運算,然後各個紋理資料分別進行處理,就可以進行完全不一樣的渲染,沒有使用固定渲染管道,而是使用GLSL中的程式設計師自定義著色器,這一點很刺激吧。
可執行demo的連線在最下面。
下次,詳細介紹一下關於紋理的引數。使用多紋理繪圖的demo