天天看點

六、WebGL入門,動畫

本節将以前的内容整合下,為以後的章節打基礎。本節主要内容是讓我們繪制的圖形動起來。

圖形動起來的原理是每一幀都繪制

下面是代碼的整體結構:

//變量
                var webgl  = null;//WebGL對象
		var vertexShaderObject   = null;//vsShader對象
		var fragmentShaderObject = null;//fsShader對象
		var programObject 		 = null;//顯示卡執行程式對象
		var triangleBuffer 		 = null;//頂點緩沖區對象
		var indexBuffer 		 = null;//索引緩沖區對象
		var v3PositionIndex 	 = 0;//位置輸入索引
		var inColor 			 = 1;//顔色輸入索引

		var unifromAnim         =   0;//anim索引
                var animTime            =   0;//計數


		//讀取shader代碼字元串
		function getShaderSource(scritptID)
		{
                  ......
		}


		//初始化工作:完成資源的加載
		/**
		*讀shader,編譯shader程式,建立顯示卡程式,連結,向顯示卡中傳輸資料。。。
		*/
		function init()
		{
                  ......
		}

		//主程式
		function WebGLStart()
		{
                   ......
		}
 		
 		//渲染
		function renderScene()
		{
                    ......
		}
		//循環
		function tick()
		{
                  ......
		}

		//重新整理
		window.requestAnimFrame = (function(){
		  return  window.requestAnimationFrame       ||
		          window.webkitRequestAnimationFrame ||
		          window.mozRequestAnimationFrame    ||
		          function( callback,element ){
		            window.setTimeout(callback, 1000 / 60);
		          };
		})();
           

我們要做的效果是讓矩形向右移動,實際上就是讓矩形的橫坐标x不斷增加。

在shader裡面的展現就是v3Position.x+anim(anim是一個增量)

其實是不斷的改變anim的值,這就要用到上節提到的uniform變量,在通過webgl.uniform1f(unifromAnim,animTime)每幀改變其值。

shader代碼如下:

<script id="shader-vs" > //頂點着色器vertexShader,處理頂點
		precision lowp float;
		attribute vec3 v3Position;
		attribute vec4 inColor;
		varying  vec4 outColor;
		uniform  float anim;
		void main(void)
		{
			outColor = inColor;
			gl_Position = vec4(v3Position.x+anim,v3Position.y,v3Position.z,1.0);
		}
	</script>

	<script id="shader-fs" >//片段着色器fragmentShader,填充顔色
		precision lowp float;
		varying  vec4 outColor;
		void main(void)
		{

			gl_FragColor = outColor;
		}//兩段shader代碼都在顯示卡在執行
	</script>
           

初始化init()代碼如下:

function init()
		{
			var canvas = document.getElementById("myCanvas");
			webgl = canvas.getContext("webgl");
			webgl.viewport(0,0,canvas.clientWidth,canvas.clientHeight);
			//先将兩段shader代碼上傳到顯示卡
			vertexShaderObject = webgl.createShader(webgl.VERTEX_SHADER);//建立一個空的vertexShader對象,裡面什麼也沒有
			fragmentShaderObject = webgl.createShader(webgl.FRAGMENT_SHADER);//同理建立一個空的fragmentShader對象
			webgl.shaderSource(vertexShaderObject,getShaderSource("shader-vs"));//相當于給vertexShader指派,使其指向shader-vs裡面的代碼字元串
			webgl.shaderSource(fragmentShaderObject,getShaderSource("shader-fs"));//相當于給fragmentShader指派,使其指向shader-fs裡面的代碼字元串
			//編譯兩段代碼,使其形成能在顯示卡執行的二進制代碼
			webgl.compileShader(vertexShaderObject);
			webgl.compileShader(fragmentShaderObject);
			//檢測編譯錯誤
			if(!webgl.getShaderParameter(vertexShaderObject,webgl.COMPILE_STATUS))
			{
				alert("error:vertexShaderObject,info:"+webgl.getShaderInfoLog(vertexShaderObject));
				return;
			}
			if(!webgl.getShaderParameter(fragmentShaderObject,webgl.COMPILE_STATUS))
			{
				alert("error:fragmentShaderObject,info:"+webgl.getShaderInfoLog(fragmentShaderObject));
				return;
			}
			programObject = webgl.createProgram();//建立一個程式,相當于建立一個空的exe檔案,前面的shader相當于兩個庫檔案
			//将exe檔案與庫檔案關聯在一起
			webgl.attachShader(programObject,vertexShaderObject);
			webgl.attachShader(programObject,fragmentShaderObject);

			webgl.linkProgram(programObject);//連結,形成一個能顯示卡上執行在可執行程式,通過programObject句柄關聯

			//檢測連結錯誤
			if(!webgl.getProgramParameter(programObject,webgl.LINK_STATUS))
			{
				alert("error:programObject");
				return;
			}
			//webgl.useProgram(programObject);//使用剛剛建立好的可執行程式,使用一個程式需要輸入輸出
            var jsArrayData = 
                [
                    //x     y       z       r       g       b       a
                    -0.5,   +0.5,   0.0,    1.0,    0.0,    0.0,    1.0,
                    +0.5,   +0.5,   0.0,    0.0,    1.0,    0.0,    1.0,
                    +0.5,   -0.5,   0.0,    0.0,    0.0,    1.0,    1.0,
                    -0.5,   -0.5,   0.0,    1.0,    1.0,    0.0,    1.0,
                ];
            var indexDatas = 
                [
                    0,1,2,
                    0,2,3,
                ];    
			webgl.bindAttribLocation(programObject,v3PositionIndex,"v3Position");
			webgl.bindAttribLocation(programObject,inColor,"inColor");
			unifromAnim = webgl.getUniformLocation(programObject,"anim");//擷取shader 中 anim 索引
			triangleBuffer = webgl.createBuffer();//在顯示卡上建立一個緩沖區
			webgl.bindBuffer(webgl.ARRAY_BUFFER,triangleBuffer);//申明緩存區的存儲類型為ARRAY_BUFFER
			webgl.bufferData(webgl.ARRAY_BUFFER,new Float32Array(jsArrayData),webgl.STATIC_DRAW);//給緩存區指派
			//建立索引緩沖區
			indexBuffer = webgl.createBuffer();
			webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER,indexBuffer);
			webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER,new Uint16Array(indexDatas), webgl.STATIC_DRAW);
		}
           

渲染renderScene(),每幀都會調用一次

function renderScene()
		{
			//繪制
			webgl.clearColor(0.0,0.0,0.0,1.0);
			webgl.clear(webgl.COLOR_BUFFER_BIT);
			webgl.bindBuffer(webgl.ARRAY_BUFFER,triangleBuffer);//使用緩沖區
			webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER,indexBuffer);//使用緩沖區
			animTime+=0.005;//每幀增加0.005
			if(animTime>=1) animTime = 0;
			webgl.useProgram(programObject);
			{
				webgl.uniform1f(unifromAnim,animTime);
				webgl.enableVertexAttribArray(v3PositionIndex);//啟用v3PositionIndex
				webgl.enableVertexAttribArray(inColor);//啟用inColor
				webgl.vertexAttribPointer(v3PositionIndex,3,webgl.FLOAT,false,4*7,0);//給v3PositionIndex傳值
				webgl.vertexAttribPointer(inColor,        4,webgl.FLOAT,false,4*7,4*3);//給inColor傳值
				webgl.drawElements(webgl.TRIANGLES,6,webgl.UNSIGNED_SHORT,0);	
			}
			//webgl.useProgram(0);
		}
           

其他部分:

//主程式
		function WebGLStart()
		{
			//!初始化
			init();
			//!進入遊戲循環
			tick();
		}
 		
		//循環
		function tick()
		{
			requestAnimFrame(tick); //注:這兩個程式不能調換位置
			renderScene();
		}
           

運作後的會看到一個向右移動的矩形

本節完

繼續閱讀