iT邦幫忙

DAY 18
1

30 天實戰跨平台行動APP系列 第 18

Day 18 WebGL 材質貼圖

今天來介紹如何在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);

將材質坐標傳入即可!


上一篇
Day 17 Star Field
下一篇
Day 19 材質貼圖 - 2
系列文
30 天實戰跨平台行動APP26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言