WebGL不同幾何圖形的渲染方式

孫群發表於2013-02-04

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

<html>

<head>
<title>WebGL Beginner's Guide - Chapter 2 - Rendering Modes</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); 
    gl_PointSize = 4.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 trapezoidVertexBuffer = null; //The vertex buffer for the trapezoid
var trapezoidIndexBuffer = null; // The index buffer for the trapezoid

var indices = []; //JavaScript array to store the indices of the trapezoid
var vertices = []; //JavaScript array to store the vertices of the trapezoid


var renderingMode = 'TRIANGLES';		

/*
* 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.vertexPositionAttribute = gl.getAttribLocation(prg, "aVertexPosition");

}		

/*
* Creates the buffers that contain the geometry of the trapezoid
*
*      #1 (-0.25,0.5)  +--------------+  (0.25,0.5)  #3
*                     /                \
*                    /                  \
*                   /          .(0,0)    \ 
*                  /                      \ 
*                 /                        \
* #0(-0.5,-0.5)  +------------+-------------+  (0.5,-0.5) #4
*                             #2(0,-0.5)
*/
function initBuffers() {
    vertices =  [
    -0.5,-0.5,0.0, 	 //Vertex 0
    -0.25,0.5,0.0, 	 //Vertex 1
    0.0,-0.5,0.0,  //Vertex 2
    0.25,0.5,0.0,  	 //Vertex 3
    0.5,-0.5,0.0	 //Vertex 4
    ]; 	

    indices = [0,1,2,0,2,3,2,3,4]; //For triangles
    
    //The following code snippet creates a vertex buffer and binds the vertices to it
    trapezoidVertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, trapezoidVertexBuffer);
    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
    trapezoidIndexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trapezoidIndexBuffer);
    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, trapezoidVertexBuffer);
    gl.vertexAttribPointer(prg.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(prg.vertexPositionAttribute);

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trapezoidIndexBuffer);
    
    switch(renderingMode){

        case "TRIANGLES": {
            indices = [0,1,2,2,3,4]; 
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
        case "LINES": {
            indices = [1,3,0,4,1,2,2,3];
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.LINES, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
        case 'POINTS': {
            indices = [1,2,3];
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.POINTS, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
        case 'LINE_LOOP': {
            indices = [2,3,4,1,0];
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.LINE_LOOP, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
        case 'LINE_STRIP': {
            indices = [2,3,4,1,0];
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.LINE_STRIP, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
        case 'TRIANGLE_STRIP': {
            indices = [0,1,2,3,4];
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.TRIANGLE_STRIP, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
        case 'TRIANGLE_FAN': {
            indices = [0,1,2,3,4];
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
            gl.drawElements(gl.TRIANGLE_FAN, indices.length, gl.UNSIGNED_SHORT,0);
            break;
        }
         
    }
 }

/**
* Render Loop
*/
function renderLoop() {
    utils.requestAnimFrame(renderLoop);
    drawScene();
}

/**
* Updates the variable renderingMode with the combo box selection.
*/
function changeRenderingMode(op){
    renderingMode = (op.options[op.selectedIndex].value);
}

/**
* 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 trapezoid (vertex buffer and index buffer)
    initBuffers();
    //Renders the trapezoid!
    renderLoop();
}
</script>
</head>

<body onLoad='runWebGLApp()'>
<div id='top'>
    <h1>WebGL Beginner's Guide - Chapter 2</h1>
    <h2>Rendering a trapezoid</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 trapezoid 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'>
    Please select one option:
    <select onChange='changeRenderingMode(this)'>
        <option value='TRIANGLES' select='selected' >TRIANGLES</option>
        <option value='LINES'>LINES</option>
        <option value='POINTS'>POINTS</option>
        <option value='LINE_LOOP'>LINE_LOOP</option>
        <option value='LINE_STRIP'>LINE_STRIP</option>
        <option value='TRIANGLE_STRIP'>TRIANGLE_STRIP</option>
        <option value='TRIANGLE_FAN'>TRIANGLE_FAN</option>
    </select>
</div>
<script>cview.run();</script>
</html>

按照幾何圖形的渲染方式有以下幾種情況:
點:POINTS
線:LINES、LINE_STRIP、LINE_LOOP
面:TRIANGLES、TRIANGLE_STRIP、TRIANGLE_FAN
在使用IBO時,對於POINTS、LINES、TRIANGLES來說,對這三者中的連續索引是獨立分組的,不同組之間沒有使用緊鄰的前面或者後面索引;對於LINE_STRIP、LINE_LOOP、TRIANGLE_STRIP來說也是對索引進行了分組,不過後面一組的索引還會用到前面一組中的索引,存在著交叉的現象;TRIANGLE_FAN是比較特殊的,首先第一個索引作為origin,然後後面每兩個數字進行獨立分組。

相關文章