今天來介紹如何在WebGL中實行材質貼圖,材質貼圖的概念如下,
假設我們將一張128 * 128 pixel 的圖片,存進材質記憶體中,並賦予他材質坐標(0~1)
之後我們再以質點的坐標與材質坐標對應,電腦就可以根據材質內容映射到多邊形上面了
首先,在WebGL中,材質是儲存在叫做WebGLTexture的物件內,我們還需要成為材質的影像物件,
所以我們宣告兩個變數
var
texture = null,
textureImage = null;
首先,我們要將圖檔讀入
function loadTexture()
{
textureImage = new Image();
textureImage.onload=function(){
setupTexture();
}
textureImage.src = "./images/yellow.jpg";
}
等到Image 物件讀取圖檔完成後,在建立材質,
要創建WebGLTexture,我們使用
texture = gl.createTexture();
來創建材質物件。我們可能會有很多個材質物件,所以我們要指定現在使用哪一個材質,呼叫
gl.bindTexture(gl.TEXTURE_2D,texture);
gl.TEXTURE_2D是指材質的種類。
接下來我們要將材質讀入記憶體
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImage);
這個函式最後一個參數就是source,就是接受Image Object的。
接著我們設定材質參數,
一張實際大小是128 * 128 像素的圖片,我們有可能把它貼到512 * 512 的區域,
也有可能貼到 64 * 64 大小的區域,就必須要進行放大跟縮小了,那在運算放大及縮小的圖像時,
要怎麼進行運算呢,例如放大,要加入本來沒有的像素進去,可以使用離他最近的像素的值(gl.NEAREST),
也可以將附近的像素平均下去計算(gl.LINEAR),縮小也是一樣的,LINEAR運算方式會比較平滑模糊,
而NEAREST的方式會比較銳利。所以分別設定放大(gl.TEXTURE_MAG_FILTER)即縮小(gl.TEXTURE_MIN_FILTER)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
將以上設定全部放進setupTexture函式中
function setupTexture()
{
texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImage);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
if( !gl.isTexture(texture) ){
console.log("Error: Texture is invalid");
}
}
接下來是材質貼圖在vertex shader 與 fragment shader中要如何操作
首先,我們要傳每個點的材質坐標進去。
因此在vertex shader中 ,加入
attribute vec2 aVertexTextureCord;
變數,這是要從外部傳入shader中的
因為材質的運算是要在fragment shader中計算的,因此我們還要將材質坐標傳到fragment shader,
所以要在創立
varying highp vec2 vVertexTextureCord;
變數
然後再main()函式中指定vVertexTextureCord的值
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vVertexTextureCord = aVertexTextureCord;
}
在 fragment shader中 ,我們也要創立材質坐標的變數,以及材質變數,sampler2D形態,
最後要呼叫材質貼圖函式texture2D,第一個參數是材質變數,第二個參數是材質坐標。
varying highp vec2 vVertexTextureCord;
uniform sampler2D uSampler;
void main(void)
{
gl_FragColor = texture2D(uSampler,vec2(vVertexTextureCord.s,vVertexTextureCord.t));
}
shader程式完成後,我們要在setupTexture中,加入啟動uSampler的程式
glProgram.samplerUniform = gl.getUniformLocation(glProgram, "uSampler");
gl.uniform1i(glProgram.samplerUniform, 0);
這裡的意思是,將shader中的uSampler變數設為TEXTURE0 材質單位(可以有多個材質)
最後的工作就是建立材質坐標,將材質坐標傳入shader中即可!
建立以下兩個變數
var
vertexTexCoordAttribute = null,
starFieldTextureCordBuffer = null;
在setupBufer中建立材質坐標buffer
starFieldTextureCordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,starFieldTextureCordBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(tempTexCoord),gl.STATIC_DRAW);
在drawScene加入
vertexTexCoordAttribute = gl.getAttribLocation(glProgram, "aVertexTextureCord”);
gl.enableVertexAttribArray(vertexTexCoordAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER,starFieldTextureCordBuffer);
gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);
將材質坐標傳入即可!