在WebGL中使用drawElements繪圖

孫群發表於2013-02-04

程式碼摘自《WebGL Beginners Guide》一書第二章的ch2_Square.html

<html>

<head>
<title>WebGL Beginner's Guide - Chapter 2 - Rendering a Square</title>

<!-- CSS Styles //-->
<link href='css/style.css' 		type='text/css' rel='stylesheet'>
<link href='css/desert.css' 	type='text/css' rel='stylesheet'/>
<link href='css/smoothness/jquery-ui-1.8.13.custom.css' type='text/css' rel='stylesheet' />

<!-- JavaScript Libraries //-->
<script type='text/javascript' src='js/jquery-1.5.1.min.js'></script>
<script type='text/javascript' src='js/jquery-ui-1.8.13.custom.min.js'></script> 
<script type='text/javascript' src='js/prettify.js'></script>
<script type='text/javascript' src='js/utils.js'></script>
<script type='text/javascript' src='js/codeview.js'></script>


<!-- Fragment Shader //-->
<script id="shader-fs" type="x-shader/x-fragment">
    #ifdef GL_ES
    precision highp float;
    #endif
    void main(void) {
        gl_FragColor = vec4(0.5,0.5,1.0, 1.0);
    }
</script>

<!-- Vertex Shader //-->
<script id="shader-vs" type="x-shader/x-vertex">
	attribute vec3 aVertexPosition;

	void main(void) {
		gl_Position = vec4(aVertexPosition,1.0); 
	}
</script>

<script id="code-js" type="text/javascript">
	var gl = null; // WebGL context
	var prg = null; // The program (shaders)
	var c_width = 0; // Variable to store the width of the canvas
	var c_height = 0; // Variable to store the height of the canvas
	
	var squareVertexBuffer = null; //The vertex buffer for the square
	var squareIndexBuffer = null; // The index buffer for the square
	
	var indices = []; //JavaScript array to store the indices of the square
	var vertices = []; //JavaScript array to store the vertices of the square
	

	/*
	* The program contains a series of instructions that tell the Graphic Processing Unit (GPU)
	* what to do with every vertex and fragment that we pass it. (more about this on chapter 3)
	* The vertex shader and the fragment shader together are called the program.
	*/
	function initProgram() {
		var fgShader = utils.getShader(gl, "shader-fs");
		var vxShader = utils.getShader(gl, "shader-vs");

		prg = gl.createProgram();
		gl.attachShader(prg, vxShader);
		gl.attachShader(prg, fgShader);
		gl.linkProgram(prg);

		if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
			alert("Could not initialise shaders");
		}

		gl.useProgram(prg);

		//The following lines allow us obtaining a reference to the uniforms and attributes defined in the shaders.
		//This is a necessary step as the shaders are NOT written in JavaScript but in a 
		//specialized language called GLSL. More about this on chapter 3.
		prg.vertexPosition = gl.getAttribLocation(prg, "aVertexPosition");
	
	}		
	
	/*
	* Creates the buffers that contain the geometry of the square
	*
	*   #0 (-0.5,0.5) +--------------+  (0.5,0.5)  #3
	*               |              |
	*               |              |
	*               |      .(0,0)  |
	*               |              |
	*               |              | 
	*   #1(-0.5,-0.5) +--------------+  (0.5,-0.5) #2
	*/
	function initBuffers() {
		
        
        vertices =  [
		-0.5,0.5,0.0, 	//Vertex 0
		-0.5,-0.5,0.0, 	//Vertex 1
		0.5,-0.5,0.0, 	//Vertex 2
		0.5,0.5,0.0]; 	//Vertex 3

		indices = [3,2,1,3,1,0];
		
		//The following code snippet creates a vertex buffer and binds the vertices to it
		squareVertexBuffer = gl.createBuffer();
		gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
		
		//The following code snippet creates a vertex buffer and binds the indices to it
		squareIndexBuffer = gl.createBuffer();
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareIndexBuffer);
		gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
	}
	
	/**
	* Draws the scene
	*/
	function drawScene(){
		gl.clearColor(0.0, 0.0, 0.0, 1.0);
		gl.enable(gl.DEPTH_TEST);
	
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		gl.viewport(0,0,c_width, c_height);
		
		gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexBuffer);
		gl.vertexAttribPointer(prg.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
		gl.enableVertexAttribArray(prg.vertexPosition);
		
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareIndexBuffer);
		gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
	}
	
	/**
	* Render Loop
	*/
	function renderLoop() {
		utils.requestAnimFrame(renderLoop);
		drawScene();
	}
	/**
	* Executes the WebGL application
	* This function is invoked on the onLoad event of the webpage. 
	*/
	function runWebGLApp(){
		//Obtains a WebGL context
		gl = utils.getGLContext('canvas-element-id');
		//Initializes the program (shaders). More about this on chapter 3!
		initProgram();
		//Initializes the buffers that we are going to use to draw the square (vertex buffer and index buffer)
		initBuffers();
		//Renders the square!
		renderLoop();
	}
	 </script>
</head>

<body onLoad='runWebGLApp()'>
<div id='top'>
	<h1>WebGL Beginner's Guide - Chapter 2</h1>
	<h2>Rendering a Square</h2>
	<div id='logo-packt'><img src='packt.gif'/></div>
	<p>WebGL uses buffers to store and process vertex and index data. The mechanism is the same whether we are rendering 
a simple object like a square or a racing car as we will see later on.</p>
</div>

<div id='contents'>
	<div id='canvasContainer'>
		<canvas id='canvas-element-id' width='480' height='400'>
			Your browser does not support the HTML5 canvas element.
		</canvas>
	</div>
</div>

<div id='bottom'>
</div>
<script>cview.run();</script>
</html>

對attribute進行賦值時,在initShaders時,首先要通過gl.getAttribLocation(shader,"attributeName")獲取attribute變數的地址,然後通過呼叫gl.enableVertexAtribArray(attributeLocation)來啟用該attribute變數(或者像上面的程式碼一樣在給attribute賦值之後再啟用它)。上面的操作只需要呼叫一次即可。然後在迴圈drawScene的時候,如果buffer之前就已經通過gl.bufferData賦值(比如在initialBuffers()的時候對其賦值),並且buffer的值沒有改變(比如座標值未變)那麼就不需要在每次渲染的時候再通過bufferData在對其賦值,只需在每次渲染的時候,通過gl.bindBuffer和gl.vertexAttribPointer將buffer的值傳遞給著色器中的attribute變數即可,對shader中的attribute變數進行賦值。

相關文章