1. 程式人生 > >[WebGL入門]二十七,多紋理

[WebGL入門]二十七,多紋理

注:文章譯自http://wgld.org/,原作者杉本雅広(doxas),文章中如果有我的額外說明,我會加上[lufy:],另外,鄙人webgl研究還不夠深入,一些專業詞語,如果翻譯有誤,歡迎大家指正。


使用多個紋理

上次介紹了WebGL中的紋理的使用方法。簡單的實現了將紋理貼到四邊形中,果然是使用圖片資料的話比較靈活吧。

那麼,這次來說說使用多個紋理來合成影象的方法,學習了這個方法之後可以再一個多邊形中使用多個紋理。

為了同時使用多個紋理,先來想想一下需要做些什麼呢?

上次已經簡單的基礎了,WebGL中管理紋理的方法是紋理單位,靈活使用這個紋理單位的話,就能實現多紋理的渲染了。

這次的demo使用下面兩個圖片。

>第一張


>第二張


下面就使用這兩張圖片來實現多紋理渲染。


著色器的修改

首先來看一下著色器的修改吧。

為了渲染多紋理,著色器一側需要準備多個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;
}
如上,接收紋理情報的sampler2D型uniform變數一共有兩個,所做的處理和之前類似或者說一樣。
使用GLSL的內建函式texture2D來獲取紋理的情報,使用頂點顏色和兩個紋理顏色計算出最終的輸出的顏色。

這次只需要修改片段著色器,頂點著色器沒有做任何改動。


javascript的修改

接著是javascript的程式碼修改,在這裡需要向新追加的uniform變數中傳入正確的紋理資料。

首先,固定的,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');
這裡很簡單,純粹的從著色器中獲取uniformLocation。
接著,準備紋理物件,這個還是使用自制的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