WebGL学习笔记03

WebGL分享 by 达达 at 2015-01-21

前一篇文章的实验代码只是绘制一个红点,实验代码中我们并没有告诉WebGL要绘制哪些顶点,顶点要以何种方式绘制。

接下来要介绍的知识点就是用来告诉WebGL要绘制哪些顶点,以及要如何绘制的:

  1. Buffer
  2. Attribute
  3. drawArrays()

首先我们需要有一组顶点数据,WebGL使用Buffer对象来存储顶点数据,因为WebGL渲染的时候用的是数据来源是显存,而我们的程序运行在内存,所以这边需要有一个把数据从内存提交到显存的过程,调用者需要告诉WebGL数据在哪里,当WebGL开始渲染的时候会将内存数据拷贝到显存中。

所以除了创建Buffer对象之外,我们还需要在程序中维护一份等待渲染的顶点集合,在JS中用Float32Array类型来表示,代码大概像这样:

var vertices = new Float32Array([
     0.0,   0.5,
    -0.5,  -0.5,
     0.5,  -0.5
]);

// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return;
}

// Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

通过bindBuffer(),我们告诉WebGL接下来要渲染的顶点数据来源是vertexBuffer这个集合,通过bufferData(),我们将内存里的待渲染顶点集合和显存中的顶点来源关联起来。

在做完这些事情之后,我们还需要告诉Vertex Shader应该如何使用这些顶点,所以这里需要用到Attribute,Attribute是Shader中的一种变量类型,调用者可以通过getAttribLocation()和vertexAttribPointer()来设置VShader的Attribute参数。

以下是加入Attribute参数的VShader:

attribute vec4 a_Position;
void main() {
    gl_Position = a_Position; // Set the vertex coordinates of the point
}

之前设置gl_Position这个内置变量的语句变成了将a_Position赋值给gl_Position。

程序中则通过以下过程设置VertexBuffer的使用:

var a_Position = gl.getAttribLocation(program, 'a_Position');
if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return;
}

// Assign the buffer object to a_Position variable
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);

其中vertexAttribPointer()的第二个参数2,用来告诉Shader,VertexBuffer中的数据是每两个一组,组成一个a_Position。因为我们要绘制的是一个二维平面的三角形,所以只需要知道每个顶点的X轴和Y轴坐标就可以了。

接着就是调用drawArrays()来进行渲染,drawArrays()的第一个参数用来告诉WebGL要如何绘制这些顶点,是要绘制成三角形还是扇面等。

完成的实验代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>WebGL Labs 02 - Triangle</title>
        <script src="GLUtil.js"></script>
        <script type="text/javascript">
// Vertex shader program
var VSHADER_SOURCE = 
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    '   gl_Position = a_Position;\n' + // Set the vertex coordinates of the point
    '}\n';

// Fragment shader program
var FSHADER_SOURCE =
    'void main() {\n' +
    '   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the point color
    '}\n';

function main() {
    // Retrieve <canvas> element
    var canvas = document.getElementById('webgl');

    // Get the rendering context for WebGL
    var gl = GLUtil.GetContext(canvas);
    if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
    }

    // Create shader program.
    var program = GLUtil.CreateProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE);
    if (!program) {
        console.log('Failed to create program for WebGL');
        return;
    }

    gl.useProgram(program);

    var vertices = new Float32Array([
         0.0,   0.5,
        -0.5,  -0.5,
         0.5,  -0.5
    ]);

    // Create a buffer object
    var vertexBuffer = gl.createBuffer();
    if (!vertexBuffer) {
        console.log('Failed to create the buffer object');
        return;
    }

    // Bind the buffer object to target
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    // Write date into the buffer object
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

    var a_Position = gl.getAttribLocation(program, 'a_Position');
    if (a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return;
    }

    // Assign the buffer object to a_Position variable
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

    // Enable the assignment to a_Position variable
    gl.enableVertexAttribArray(a_Position);

    // Specify the color for clearing <canvas>
    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    // Clear <canvas>
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Draw a point
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
        </script>
    </head>
    <body onload="main()">
        <center style="margin-top:100px">
            <canvas id="webgl" width="400" height="400">
            Please use a browser that supports "canvas"
            </canvas>
        </center>
    </body>
</html>