WebGL入门教程(二)-webgl绘制三角形

时间:2024-02-21 16:20:44

前面已经介绍过了webgl,WebGL入门教程(一)-初识webgl(http://www.cnblogs.com/bsman/p/6128447.html),也知道了如何绘制一个点,接下来就用webgl画出一个三角形。

效果图:

 

WebGL入门教程(一)-初识webgl中,知道如何绘制一个点

//绘制一个点
gl.drawArrays(gl.POINTS, 0, 1);

但是图形是有多个点组成,那么就应该考虑如何绘制多个点,WebGL提供了一种很方便的机制,缓冲区对象(buffer object),它是WebGL系统中的一块内存区域,它可以一次性向着色器传入多个顶点的数据,然后将这些数据保存在其中,供顶点着色器使用。

首先先找到三个点,操作步骤:

  1.创建HTML5 canvas

  2.获取画布 canvas 的 ID

  3.获取WebGL

  4.编译着色器

  5.使用缓冲区对象向顶点传入多个顶点数据

  6.绘制图像

以上1~4参考:http://www.cnblogs.com/bsman/p/6128447.html

 4.编译着色器

修改顶点着色器,去掉gl_PointSize,这个只有绘制点的时候才有用

//顶点着色器程序
    var VSHADER_SOURCE =
        "attribute vec4 a_Position;" +
        "void main() {" +
            //设置坐标
        "gl_Position = a_Position; " +
        "} ";

 

 5.使用缓冲区对象向顶点传入多个顶点数据又分为五步

 5.1创建缓冲区对象

 //创建缓冲区对象
  var vertexBuffer = gl.createBuffer();

 5.2绑定缓冲区对象

//将缓冲区对象绑定到目标
 gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);

其中gl.ARRAY_BUFFER表示缓冲区对象包含了顶点的数据,要是换成gl.ELEMENT_ARRAY_BUFFER则表示包含了顶点的索引;vertexBuffer表示上一步创建的缓存区对象。

 5.3将数据写入缓冲区对象

//向缓冲区写入数据
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);

其中:gl.ARRAY_BUFFER表示目标;vertices表示写入缓存区对象的数据(类型化数组);第三个参数有3种(

gl.STATIC_DRAW:表示只会向缓存区对象写入一次数据,但需要绘制很多次;
gl.STREAM_DRAW:表示只会向缓存区对象写入一次数据,然后绘制若干次;
gl.DYNAMIC_DRAW:表示会向缓存区对象多次写入数据,并绘制很多次;

其中第二个参数,类型化数组是WEBGL为了优化性能引入的一种特殊的数组,该数组不支持push,pop有(

Int8Array :8位整形数

UInt8Array :8位无符号整形数

Int16Array :16位整形数

UInt8Array :16位无符号整形数

Int32Array :32位整形数

UInt8Array :32位无符号整形数

Float32Array :单精度32位浮点数

Float64Array :双精度64位浮点数

)属性方法有get(index)、set(index,value)、set(array,offset)、length

这种数组一定要new,否则报错,错误信息如下:

GL ERROR :GL_INVALID_OPERATION :glDrawArrays: attempt to access out of range vertices in attribute 0

例如:

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

 5.4将缓冲区对象分配给一个attribute变量

 //将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

第一个参数:指定待分配attribute变量的存储位置

第二个参数:指定缓存区中每个顶点的分量个数(1~4)

第三个参数:类型有,gl.UNSIGNED_BYTE无符号字节,gl.SHORT短整数,gl.UNSIGNED_SHORT无符号短整数,gl.INT整型,gl.UNSIGNED_INT无符号整型,gl.FLOAT浮点型。

第四个参数:表示是否将非浮点型的数据归到[0,1][-1,1]区间

第五个参数:相邻两个顶点的字节数。默认为0

第六个参数:表示缓存区对象的偏移量(以字节为单位),就是attribute变量从缓冲区中的何处开始存储。

 5.5开启attribute变量

//连接a_Position变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);

就是开启attribute变量,是缓存区对attribute变量分配生效,使顶点着色器能够访问缓冲区内的数据。

  6.绘制图像

WebGL可以绘制的图形有:
gl.POINTS 一系列点,绘制v0,v1……。
线段 gl.LINES 一系列单独的线段,绘制(v0,v1),(v2,v3)……如果是奇数,最后一个省略。
线条 gl.LINE_STRIP 一系列连接的线段,绘制(v0,v1),(v1,v2),(v2,v3)……除了第一个和最后一个,其他的点点即是起点又是终点。
回路 gl.LINE_LOOP 一系列连接的线段,绘制(v0,v1),(v1,v2),(v2,v3)……(vn,v0),最后一个点会连接起点。
三角形 gl.TRIANGLES 一系列单独的三角形,绘制(v0,v1,v2),(v3,v4,v5)……如果不是3的倍数,剩下的将会被忽略。
三角带 gl.TRIANGLES_STRIP 一系列连接的三角形,绘制(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)……以此类推,第二个是(v2,v1,v3)而不是(v1,v2,v3)是为了保持绘制按照逆时针绘制
gl.drawArrays(gl.TRIANGLES, 0, n);

 

 

完整代码:

html代码

<!DOCTYPE html>
<html>
<head>
    <meta lang="en">
    <meta charset="UTF-8">
    <title>WebGL study</title>
    <link href="../ClickedPoints/style.css">
    <script type="text/javascript" src="../Triangle/js.js"></script>
</head>
<body>
<canvas id="canvas" width="200px" height="200px"></canvas>
</body>
</html>

 

javascript代码

/**
 * Created by HBX on 2016/12/3.
 */
window.onload = function () {

    //顶点着色器程序
    var VSHADER_SOURCE =
        "attribute vec4 a_Position;" +
        "void main() {" +
            //设置坐标
        "gl_Position = a_Position; " +
        "} ";

    //片元着色器
    var FSHADER_SOURCE =
        "void main() {" +
            //设置颜色
        "gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);" +
        "}";
    //获取canvas元素
    var canvas = document.getElementById(\'canvas\');
    //获取绘制二维上下文
    var gl = canvas.getContext(\'webgl\');
    if (!gl) {
        console.log("Failed");
        return;
    }
    //编译着色器
    var vertShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertShader, VSHADER_SOURCE);
    gl.compileShader(vertShader);

    var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragShader, FSHADER_SOURCE);
    gl.compileShader(fragShader);
    //合并程序
    var shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertShader);
    gl.attachShader(shaderProgram, fragShader);
    gl.linkProgram(shaderProgram);
    gl.useProgram(shaderProgram);

    //获取坐标点
    var a_Position = gl.getAttribLocation(shaderProgram, \'a_Position\');

    if (a_Position < 0) {
        console.log(\'Failed to get the storage location of a_Position\');
        return;
    }

    var n = initBuffers(gl,shaderProgram);

    if(n<0){
        console.log(\'Failed to set the positions\');
        return;
    }
    // 清除指定<画布>的颜色
    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    // 清空 <canvas>
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.drawArrays(gl.TRIANGLES, 0, n);
}

function initBuffers(gl,shaderProgram) {
    var vertices = new Float32Array([
        0.0, 0.5, -0.5, -0.5, 0.5, -0.5
    ]);
    var n = 3;//点的个数
    //创建缓冲区对象
    var vertexBuffer = gl.createBuffer();
    if(!vertexBuffer){
        console.log("Failed to create the butter object");
        return -1;
    }
     //将缓冲区对象绑定到目标
    gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
    //向缓冲区写入数据
    gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
    //获取坐标点
    var a_Position = gl.getAttribLocation(shaderProgram, \'a_Position\');
    //将缓冲区对象分配给a_Position变量
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    //连接a_Position变量与分配给它的缓冲区对象
    gl.enableVertexAttribArray(a_Position);
    return n;

}