WebGL入门教程(二)-webgl绘制三角形
前面已经介绍过了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; }