iT邦幫忙

DAY 19
0

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

Day 19 材質貼圖 - 2

  • 分享至 

  • twitterImage
  •  

昨天我們加入材質貼圖後,原本只是很多個平行螢幕的正方形,變成以下樣子:

是不是很不錯呢? 只是這裡面的星星只有一種!有點單調,所以我另外找了幾種星星的圖片,

希望能讓宇宙繽紛一點。這就牽涉到你有多種材質在要處理。假設我們總共有五種星星要貼圖,

我們先從fragment shader開始,記得fragment shader可以處理材質貼圖相關的變化。

因為有五種星星,所以我們另外增加了四個sampler2D變數

uniform sampler2D uSampler;

uniform sampler2D uSampler2;

uniform sampler2D uSampler3;

uniform sampler2D uSampler4;

uniform sampler2D uSampler5;

在fragment shader的主程式中,我們可以想見一定要判斷,什麼時候要用哪個材質貼圖,

這就先留到最後再處理,先回到webgl程式。

首先現在材質跟影像都改成陣列,我們也將星星索引存成變數方便辨識

var STAR_TEXTURE_1 = 0;
STAR_TEXTURE_2 = 1,
STAR_TEXTURE_3 = 2,
STAR_TEXTURE_4 = 3,
STAR_TEXTURE_5 = 4;

texture = [];
textureImage = [];

接下來我們將setupTexture 改成 setupTexture(i)

function setupTexture(i)

{

  gl.activeTexture(gl.TEXTURE0 + i);

  texture[i] = gl.createTexture();

  gl.bindTexture(gl.TEXTURE_2D, texture[i]);

  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImage[i]);

  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

  if( !gl.isTexture(texture[i]) )

  {

        console.error("Error: Texture is invalid");

  }

}

然後將loadTexture 改寫成

function loadTexture()
{	
	
	textureImage[0] = new Image();
	
	textureImage[0].onload = function() {
		setupTexture(0);
		
		glProgram.samplerUniform =  gl.getUniformLocation(glProgram, "uSampler");

		
		gl.uniform1i(glProgram.samplerUniform, 0);
	}
	
	textureImage[0].src = "./images/star1.jpg";

	textureImage[1] = new Image();
	
	textureImage[1].onload = function() {
		setupTexture(1);
		
		glProgram.samplerUniform1 =  gl.getUniformLocation(glProgram, "uSampler2");

		
		gl.uniform1i(glProgram.samplerUniform1, 1);
	}
	
	textureImage[1].src = "./images/star2.jpg";

	textureImage[2] = new Image();
	
	textureImage[2].onload = function() {
		setupTexture(2);
		
		glProgram.samplerUniform2 =  gl.getUniformLocation(glProgram, "uSampler3");

		
		gl.uniform1i(glProgram.samplerUniform2, 2);
	}
	
	textureImage[2].src = "./images/star3.jpg";

	textureImage[3] = new Image();
	
	textureImage[3].onload = function() {
		setupTexture(3);
		
		glProgram.samplerUniform3 =  gl.getUniformLocation(glProgram, "uSampler4");

		
		gl.uniform1i(glProgram.samplerUniform3, 3);
	}
	
	textureImage[3].src = "./images/star4.jpg";

	textureImage[4] = new Image();
	
	textureImage[4].onload = function() {
		setupTexture(4);
		
		glProgram.samplerUniform4 =  gl.getUniformLocation(glProgram, "uSampler5");

		
		gl.uniform1i(glProgram.samplerUniform4, 4);
	}
	
	textureImage[4].src = "./images/star5.jpg";

		
	
}

如此一來設定材質的部分就完成了

接下來,我們要思考怎麼繪圖。

我是這麼想:將亂數產生的星星分成五群,每一群在繪圖時,就用不同的星星貼圖!

但是其實我們不需要產生五組vertices資料,只要產生五組繪圖的index資料!

所以我們將 starFieldIndexBuffer 改成陣列

var starFieldIndexBuffer=[]; 

然後將 starFiled 輸入的參數中的星星數量number,改成groupNumber 與 number

變成說有幾種星星,然後每一種星星的數量有多少。

產生indice的函式變成

for(var j=0;j<this.groupNumber;j++){
		
		var indiceArray = [];
		for(var i=0;i<this.number;i++){

			indiceArray.push((j*this.number+i)*4+0);
			indiceArray.push((j*this.number+i)*4+1);
			indiceArray.push((j*this.number+i)*4+2);

			indiceArray.push((j*this.number+i)*4+2);
			indiceArray.push((j*this.number+i)*4+3);
			indiceArray.push((j*this.number+i)*4+0);
			
		}
		this.starFieldIndiceArrayForPlane.push(indiceArray);
	}

然後再setupBuffer函式中,改成

for(var i=0;i<starfieldVerticeIndiceArray.length;i++){


starFieldIndexBuffer[i] = gl.createBuffer();

starFieldIndexBuffer[i].number_vertex_points = starfieldVerticeIndiceArray[i].length;



gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, starFieldIndexBuffer[i]);

gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(starfieldVerticeIndiceArray[i]), gl.STATIC_DRAW);



}

最後在drawScene中,將drawElement部分改成

for(var i=0;i<starFieldIndexBuffer.length;i++){


gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, starFieldIndexBuffer[i]);  

gl.drawElements(gl.TRIANGLES, starFieldIndexBuffer[i].number_vertex_points, gl.UNSIGNED_SHORT, 0);


}

是不是覺得怪怪的,好像少了要跟shader說現在要用什麼材質繪圖的部分。

首先再迴圈中,加入

gl.bindTexture(gl.TEXTURE_2D, texture[i]);

接著回到fragment shader,我們加入一個uniform變數來控制現在要用什麼材質來繪圖

然後將main函式改寫為

precision mediump float;

varying vec2 vTextureCoord;

uniform sampler2D uSampler;
uniform sampler2D uSampler2;
uniform sampler2D uSampler3;
uniform sampler2D uSampler4;
uniform sampler2D uSampler5;

uniform int textureSwitch;

void main(void) {
    
    
    if (textureSwitch==1) {
        gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));

    }
    else if(textureSwitch==2){
        gl_FragColor = texture2D(uSampler2, vec2(vTextureCoord.s, vTextureCoord.t));

    }
    else if(textureSwitch==3){
        gl_FragColor = texture2D(uSampler3, vec2(vTextureCoord.s, vTextureCoord.t));

    }
    else if(textureSwitch==4){
        gl_FragColor = texture2D(uSampler4, vec2(vTextureCoord.s, vTextureCoord.t));

    }
    else if(textureSwitch==5){
        gl_FragColor = texture2D(uSampler5, vec2(vTextureCoord.s, vTextureCoord.t));

    }
    else{
        gl_FragColor = vec4(1.0,0.0,0.0,1.0);

    }
    
}

註:switch似乎編譯不會過

應該很簡單!接著再drawScene 的迴圈中加入

	glProgram.textureSwitch = gl.getUniformLocation(glProgram,"textureSwitch"); 
	for(var i=0;i<starFieldIndexBuffer.length;i++){
		 
		gl.bindTexture(gl.TEXTURE_2D, texture[i]);
		gl.uniform1i(glProgram.textureSwitch,i+1);
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, starFieldIndexBuffer[i]);  
		gl.drawElements(gl.TRIANGLES, starFieldIndexBuffer[i].number_vertex_points, gl.UNSIGNED_SHORT, 0);

}

先抓取textureSwitch變數的位置,然後再將目前的值傳進去!

到目前為止就大功告成囉!做出來的效果明天揭曉!


上一篇
Day 18 WebGL 材質貼圖
下一篇
Day 20 地球圖資
系列文
30 天實戰跨平台行動APP26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言