文章目录
- 前言
- gl.drawArrays()——按顶点绘制
- 可绘制基本类型
- 绘制矩形和圆形
- gl.drawElements()——按索引绘制
- 使用规范
- 绘制矩形
- 总结
前言
gl.drawArrays()作为webgl中常用的函数图形绘制方法,可以在浏览器按照指定的模式绘制图形,与之相对的gl.drawElements()函数也是常用的绘制函数,本文将介绍二者的区别与使用。
gl.drawArrays()——按顶点绘制
可绘制基本类型
gl.drawArrays(mode, first, count)的使用在webgl图形绘制基础中有过详细的介绍,它的mode参数其实十分强大,可以按照不同的规则绘制不同的图形,可直接绘制的图形有七种,这七种图形是绘制其它各种复杂图形的基础。
参数名 | 图形 | 描述 |
---|---|---|
gl.POINTS | 点 | 一系列点,依次绘制 |
gl.LINES | 线段 | 每两个一组绘制线段,若点的数目为奇数,最后一个点会被舍弃 |
gl.LINES_STRIP | 线条 | 所有的点依次相连 |
gl.LINE_LOOP | 回路 | 再线条的基础上,将首尾点相连 |
gl.TRIANGLES | 三角形 | 每三个一组绘制三角形,若点的数目无法被三整除,剩余的点会被舍弃 |
gl.TRIANGLES_STRIP | 三角带 | 一系列条带状的三角形,每个三角形都存在一条边共享 |
gl.TRIANGLES_FAN | 三角扇 | 类似于扇形的图形 |
绘制矩形和圆形
绘制矩形可以通过两个三角形完成,要注意顶点数据必须按照三角形逆时针
方向给出。
const vertices = new Float32Array([
// 第一个三角形
-0.3, 0.3,
-0.3, -0.3,
0.3, -0.3,
// 第二个三角形
0.3, -0.3,
0.3, 0.3,
-0.3, 0.3,
])
绘制圆形的原理相似,当相同大小的三角形具备同一个顶点
并组成一个闭环时,就可以近似视为圆。三角形数越多,圆形越近似。
当用十个点绘制时:
const _circle = [];
for (let i = 0; i <= 10; i++) {
const angle = i * Math.PI * 2 / 10; // 把2Π分成10份
_circle.push(0 + 0.3 * Math.sin(angle), 0 + 0.3 * Math.cos(angle));
}
const circle = new Float32Array(_circle);
当用一百个点绘制时:
const _circle = [];
for (let i = 0; i <= 100; i++) {
const angle = i * Math.PI * 2 / 100; // 把2Π分成100份
_circle.push(0 + 0.3 * Math.sin(angle), 0 + 0.3 * Math.cos(angle));
}
const circle = new Float32Array(_circle);
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webgl</title>
<script src="./lib.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
padding: 0;
}
canvas {
margin: 50px 30px;
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
/** @type {HTMLCanvasElement} */
//------------------------------------------------------创建画布
// 获取webgl绘图上下文
const gl = canvas.getContext('webgl');
if (!gl) {
throw new Error('WebGL not supported');
}
gl.clear(gl.COLOR_BUFFER_BIT)
const vertex = `
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
}
`
const fragment = `
precision highp float;
void main(){
gl_FragColor =vec4(1.0,0.0,1.0,1.0);
}
`
// 创建program
const program = initShader(gl, vertex, fragment)
// 获取attribute变量的数据存储位置
const aPosition = gl.getAttribLocation(program, 'aPosition');
// 创建缓冲区对象
const buffer = gl.createBuffer();
// 绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// 传入的数据
const vertices = new Float32Array([
// 第一个三角形
-0.3, 0.3,
-0.3, -0.3,
0.3, -0.3,
// 第二个三角形
0.3, -0.3,
0.3, 0.3,
-0.3, 0.3,
])
const _circle = [];
for (let i = 0; i <= 100; i++) {
const angle = i * Math.PI * 2 / 100; // 把2Π分成100份
_circle.push(0 + 0.3 * Math.sin(angle), 0 + 0.3 * Math.cos(angle));
}
const circle = new Float32Array(_circle);
// 开辟空间并写入数据
gl.bufferData(gl.ARRAY_BUFFER, circle, gl.STATIC_DRAW)
// 缓冲区对象分配给attribute变量
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0)
// 开启attribue变量
gl.enableVertexAttribArray(aPosition)
// 开始绘制
gl.drawArrays(gl.TRIANGLE_FAN, 0, 1000)
</script>
</body>
</html>
gl.drawElements()——按索引绘制
使用规范
在绘制矩形时,实际上只需要四个顶点,可是使用gl.drawArrays却存储了六个顶点,每个顶点大小为 4 * 6 = 24 个字节,绘制矩形就浪费了 48
字节的空间,为了避免这种浪费,WebGL 提供了按照顶点索引进行绘制的方法gl.drawElements
节省存储空间。
drawElements(mode, count, type, offset):将指定的缓冲区设置为预设的值
- mode:绘制模式,与gl.drawArrays() 相同
- count: 绑定元素数组缓冲区的元素数
- type:元素数组缓冲区中值的类型,枚举如下:
— gl.UNSIGNED_BYTE
— gl.UNSIGNED_SHORT- offset:元素数组缓冲区中的字节偏移量
绘制矩形
效果
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webgl</title>
<script src="./lib.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
padding: 0;
}
canvas {
margin: 50px 30px;
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
/** @type {HTMLCanvasElement} */
//------------------------------------------------------创建画布
// 获取webgl绘图上下文
const gl = canvas.getContext('webgl');
if (!gl) {
throw new Error('WebGL not supported');
}
gl.clear(gl.COLOR_BUFFER_BIT)
const vertex = `
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
}
`
const fragment = `
precision highp float;
void main(){
gl_FragColor =vec4(1.0,0.0,1.0,1.0);
}
`
// 创建program
const program = initShader(gl, vertex, fragment)
// 获取attribute变量的数据存储位置
const aPosition = gl.getAttribLocation(program, 'aPosition');
// 创建缓冲区对象
const buffer = gl.createBuffer();
// 绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// 传入的数据
const vertices = new Float32Array([
// 第一个三角形
-0.3, 0.3,
-0.3, -0.3,
// 0.3, -0.3,
// 第二个三角形
0.3, -0.3,
0.3, 0.3,
// -0.3, 0.3,
])
// 索引缓冲区
const index = new Uint16Array([0, 1, 2, 0, 2, 3])
// 开辟空间并写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
// 缓冲区对象分配给attribute变量
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0)
// 开启attribue变量
gl.enableVertexAttribArray(aPosition)
const indexBuffer = gl.createBuffer();
//绑定索引缓冲区
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
//向索引缓冲区传递索引数据
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);
// 开始绘制
gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);
</script>
</body>
</html>
总结
gl.drawArrays()
- 可绘制基本类型
- gl.drawArrays()绘制矩形和圆形
gl.drawElements()按照索引绘制
- 使用规范
- 绘制矩形