1、绘制多个点的过程
绘制一个点的时候,webgl
程序的执行过程是这样的:
- 获取 webgl 绘图上下文
- 初始化着色器
- 设置 canvas 背景色
- 清空 canvas
- 开始绘制
上面是绘制一个点的过程,但是如果想要绘制多个点话,就需要多次重复上面的步骤吗?
webgl
提供了一种机制可以向缓存中一次存储多个顶点的信息,然后只需要循环的调用 着色器程序即可,而不需要循环重复上面的步骤。
因此上面的步骤中多个一个 步骤 :设置点的坐标信息 然后再清空 canvas
再绘制
2、创建三个顶点
具体步骤如下
1、首先顶点着色器和片元着色器不用换
attibute vec4 a_Position;
void main(){
gl_Position = a_Position;
gl_PointSize = 10.0;
}
void main(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
2、设置顶点位置
- 1、创建缓冲区对象 –
gl.createBuffer()
- 2、绑定缓冲区对象 –
gl.bindBuffer()
- 3、将数据写入缓冲区对象 –
gl.bufferData()
- 4、将缓冲区对象分配给一个
attribute
变量gl.vertexAttribPointer()
- 5、开启
attribute
变量 –gl.enableVertexAttribArray()
缓冲区对象: 缓冲区对象是 webgl 系统中的一块存储区,我们可以在缓冲区对象中保存想要绘制的所有顶点的数据,并且可以使用也可以不使用;
使用缓冲区对象向顶点着色器传入数据,需要遵守以上五个步骤;
具体代码如下
var vertices = new Float32Array([
0.0, 0.5, 0.5, -0.5, -0.5, -0.5
]);
var n = vertices.length / 2;
// 1. 创建缓冲区对象
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('创建缓冲区对象失败!');
return -1;
}
// 2. 绑定缓冲区对象到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 3. 将数据写入到缓冲区对象
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('获取attribute变量失败!');
return -1;
}
// 4. 将缓冲区对象分配给attribute变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// 5. 开启attribute变量
gl.enableVertexAttribArray(a_Position);
具体细节如下
1、 创建缓冲区对象
var vertexBuffer = gl.createBuffer();
创建缓冲区对象不用传递参数,创建一个对象就存留在 webgl
的缓冲区中,不删除则一致存在
删除缓冲区的方法
gl.deleteBuffer(buffer);
删除的时候传入的参数是,缓冲区的引用
2、绑定缓冲区对象到目标
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
将缓冲区对象绑定到 webgl
中已经存在的目标上,目标表示缓冲区对象的用途,这里传递的是gl.ARRAY_BUFFER
表示缓冲区对象中包含顶点的数据,另外还可以传递gl.ELEMENT_ARRAY_BUFFER
这个表示缓冲区对象包含了顶点的索引值;
第二个参数是刚刚创建的缓冲区对象
3、将数据写入缓冲区对象
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DEAW)
这个方法的作用是将顶点数组vertices
的数据,写入到已经绑定了缓冲区的对象中,第三个参数是写入和绘制次数限制;
4、分配缓冲区对象
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
之前绘制一个顶点的时候,是通过gl.vertexAttrib[123]f()
为attribute
分配变量值,但是这个方法一次只能分配一个值,而此时我们需要将整个缓冲区里面的值全部分配给 attribute
变量,此时就需要使用gl.vertexAttribPointer()
它可以将整缓冲区对象的引用分配给attribute
变量;
gl.vertexAttribPointer(location, size, type, normalized, stride,offset)
具体参数
location
:待分配的attribute
变量size
:指定缓冲区每个顶点的分量个数(1 - 4)type
:指定数据格式normalize
:表示浮点型的数据是否归一化到[0, 1]或者[-1,1]区间stride
:指定相邻两个顶点间的字节数,默认为0
offset
:指定缓冲区对象的偏移量,以字节为单位,若是从起始位置开始,offset设置0
5、开启 attribute 变量
为了使顶点着色器能够访问缓冲区的数据,还需要开始attribute
变量
gl.enableVertexAttribArray(a_Position);
此时缓冲区对象就和attribute
之间建立了连接,也可也通过以下方法来关闭连接
gl.disableVertexArray(location)
通过以上五个步骤就可以绘制顶点了,具体的绘制方式和绘制次数还需要在gl.drawArrays()
中,来设置;
gl.drawArrays(gl.POINTS, 0, 3);
上面代码表示,绘制点从第一个点开始,绘制三个点,此时顶点着色器执行了3
次,也就是最后一个参数的设置;
示例地址
绘制多个点
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/common.css">
</head>
<body>
<canvas id="webgl" width="512" height="512"></canvas>
</body>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script>
// 顶点着色器
var vertex_shader_source = '' +
'attribute vec4 a_Position;' +
'void main() {' +
' gl_Position = a_Position;' +
' gl_PointSize = 10.0;' +
'}';
// 片元着色器
var fragment_shader_source = '' +
'void main(){' +
' gl_FragColor = vec4(0.5, 0.0, 0.5, 1.0);' +
'}';
(function () {
// 获取canvas对象
var canvas = document.getElementById('webgl');
// 获取webgl 上下文对象
var gl = getWebGLContext(canvas);
// 初始化着色器
if (!initShaders(gl, vertex_shader_source, fragment_shader_source)) {
console.log('初始化着色器失败!');
return false;
}
// 设置顶点位置
var n = initVertexBuffer(gl);
if (n < 0) {
console.log('顶点写入缓存失败!');
return false;
}
// 设置清空颜色
gl.clearColor(0.0, 0.5, 0.5, 1.0);
// 清空canvas
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, n);
// 将顶点信息写入缓存区
function initVertexBuffer(gl) {
var vertices = new Float32Array([
0.0, 0.5, 0.5, -0.5, -0.5, -0.5
]);
var n = vertices.length / 2;
// 创建缓冲区对象
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('创建缓冲区对象失败!');
return -1;
}
// 绑定缓冲区对象到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 将数据写入到缓冲区对象
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('获取attribute变量失败!');
return -1;
}
// 将缓冲区对象分配给attribute变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// 开启attribute变量
gl.enableVertexAttribArray(a_Position);
return n;
}
}());
</script>
</html>