前面已经介绍过了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;
}