WebGl 使用缓冲区对象绘制多个点
缓冲区对象是WebGL系统中为一块内存区域,可以一次性地向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,供顶点着色器使用。
1.类型化数组类型
在 webgl 中,需要处理大量的相同类型数据,所以引入类型化数组,这样程序就可以预知到数组中的数据类型,提高性能。
- Int8Array:8位整型
- UInt8Array: 8位无符号整型
- Int16Array: 16位整型
- UInt16Array:16位无符号整型
- Int32Array:32位整型
- UInt32Array:32位无符号整型
- Float32Array:单精度32位浮点型
- Float64Array:双精度64位浮点型
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
2.创建缓冲区对象
const buffer = gl.createBuffer();
3.绑定缓冲区对象
gl.bindBuffer(target, buffer)
(1)target参数有两种:
- gI.ARRAY_BUFFER: 表示缓冲区存储的是顶点的数据
- 9I.ELEMENT_ARRAY_BUFFER:表示缓冲区存储的是顶点的索引值
(2)buffer:已经创建好的缓冲区对象
4.将数据写入缓冲区对象
gl.bufferData(target, data, type)
(1)target: 类型同 gl.bindBuffer 中的 target
(2)data:写入缓冲区的顶点数据,如程序中的 points
(3)type表示如何使用缓冲区对象中的数据,分为以下几类:
- gI.STATIC DRAW:写入一次,多次绘制。
- gI.STREAM_DRAW:写入一次,绘制若干次。
- gI.DYNAMIC_DRAW:写入多次,绘制多次。
5.将缓冲区对象分配给一个attribute变量
gl.vertexAttribPointer(location, size, type, normalized, stride, offset)
(1)location:attribute 变量的存储位置
(2)size:指定每个顶点所使用数据的个数
(3)type:指定数据格式
- gI.FLOAT:浮点型
- 9I.UNSIGNED_BYTE:无符号字节
- gI.SHORT:短整型
- gI.UNSIGNED_SHORT:无符号短整型
- gI.INT:整型
- gI.UNSIGNED_INT:无符号整型
(4)normalized:表示是否将数据归一化到[0,1][-1,1]这个区间
(5)stride:两个相邻顶点之间的字节数
(6)offset:数据偏移量
6.开启attribute变量
gl.enableVertexAttribArray(location)
(1)location: attribute 变量的存储地址
(2)gl.disableVertexAttribArray(aPosition); 使用此方法禁用attribute变量
7.完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
}
canvas {
margin: 50px auto;
display: block;
background: pink;
}
</style>
<title>修改点的颜色</title>
</head>
<body>
<canvas id="canvas" width="400" height="400">
此浏览器不支持canvas
</canvas>
<script src="./js/index.js"></script>
<script>
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 顶点着色器源码
const vertexShaderSource = `
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
}`
// 片源着色器源码
const fragmentShaderSource = `
void main() {
gl_FragColor = vec4(0.0,0.0,0.0,1.0); // r, g, b, a
}`
const program = initShader(gl, vertexShaderSource, fragmentShaderSource);
const aPosition = gl.getAttribLocation(program, 'aPosition');
// 1.创建顶点数据
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
// 2.创建缓冲区对象
const buffer = gl.createBuffer();
// 3.绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
// 4.将数据写入缓冲区对象,这里参数选择写入一次,多次绘制
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW)
// 5.将缓冲区对象分配给一个attribute变量
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
// 6.开启attribute变量
gl.enableVertexAttribArray(aPosition)
// 7.绘制三个点
gl.drawArrays(gl.POINTS, 0, 3);
// 着色器
function initShader(gl, vertexShaderSource, fragmentShaderSource) {
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
return program;
}
</script>
</body>
</html>