WebGL 基础:画个矩形
- 💡 通过三角形构建矩形
- 💡 索引绘制的使用方法
基本三角形构建矩形
- 源码
关于顶点绘制顺序:
WebGL 会认为顶点顺序为逆时针时代表正面,反之则是背面,区分正面、背面的目的在于,如果开启了背面剔除功能的话,背面是不会被绘制的。
所以组成三角形的顶点顺序要按照逆时针排序。
一个矩形可以由两个三角形组成(4 个点,其中 2 点共用)
js
const positions = [
30,
30,
255,
0,
0,
1, // V0
30,
300,
255,
0,
0,
1, // V1
300,
300,
255,
0,
0,
1, // V2
30,
30,
0,
255,
0,
1, // V0
300,
300,
0,
255,
0,
1, // V2
300,
30,
0,
255,
0,
1 // V3
]
然后利用一个 buffer 读取多种数据绘制两个三角形
索引方式绘制
- 源码 上面的绘制重复了两个点,浪费!使用
gl.drawElements(mode, count, type, offset)
可以避免重复定义顶点。 - mode:指定要渲染的图元类型。(枚举类型)
gl.POINTS
gl.LINE_STRIP
gl.LINE_LOOP
gl.LINES
gl.TRIANGLES
gl.TRIANGLE_STRIP
gl.TRIANGLE_FAN
- count:渲染的元素数量
- type:指定元素数组缓冲区(索引缓冲区)中的值的类型
gl.UNSIGNED_BYTE
gl.UNSIGNED_SHORT
- offset 偏移量
js
gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_BYTE, 0)
表示:采用三角形绘制,共绘制 3 个顶点,顶点索引类型是无符号 8 位整数值,从顶点索引数组的开始位置绘制。
准备四个顶点的顶点数组,还有相对应的索引数组,索引中的值分别对应使用的顶点 index
js
// 存储顶点信息的数组
const positions = [
30,
30,
255,
0,
0,
1, // V0
30,
300,
255,
0,
0,
1, // V1
300,
300,
255,
0,
0,
1, // V2
300,
30,
0,
255,
0,
1 // V3
]
// 存储顶点索引的数组
const indices = [
0,
1,
2, // 第一个三角形
0,
2,
3 // 第二个三角形
]
创建索引数组缓冲区(gl.ELEMENT_ARRAY_BUFFER
):
js
const indicesBuffer: WebGLBuffer = gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW)
然后绘制
js
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)
三角带绘制矩形
准备四个顶点进行绘制,需要注意顶点顺序。第一个三角形的顶点为 v0,v1,v2,第二个三角形的顶点为 v2,v1,v3
js
positions = [
30,
300,
255,
0,
0,
1, // V0
300,
300,
255,
0,
0,
1, // V1
30,
30,
255,
0,
0,
1, // V2
300,
30,
0,
255,
0,
1 // V3
]
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
三角扇绘制矩形
需要用 6 个顶点绘制 4 个三角形。v0 点为中心点,向四边衍生四个点,形成 4 个三角形。
js
positions = [
165,
165,
255,
255,
0,
1, // V0
30,
30,
255,
0,
0,
1, // V1
30,
300,
255,
0,
0,
1, // V2
300,
300,
255,
0,
0,
1, // V3
300,
30,
0,
255,
0,
1, // V4
30,
30,
255,
0,
0,
1 // V1
]
gl.drawArrays(gl.TRIANGLE_FAN, 0, positions.length / 6)
三角形绘制圆形
以三角扇的顶点作为圆心,绘制数个三角形,数量越多,圆形越平滑。(...去复习三角形三边计算吧 🙉🙉🙉)
顶点数量相应的变多,内存占用会变大
js
/**
* @description:
* @param {*} x 圆心x坐标
* @param {*} y 圆心y坐标
* @param {*} radius 半径
* @param {*} n 三角形数量
*/
function createCircleVertex (x: number, y: number, radius: number, n: number): [number] {
const positions = [x, y, 255, 0, 0, 1]
for (let i = 0; i <= n; i++){
const angle = (i * Math.PI * 2) / n
positions.push(x + radius * Math.sin(angle), y + radius * Math.cos(angle), 255, 0, 0, 1)
}
return positions
}
const positions = createCircleVertex(100, 100, 50, 30)
三角形绘制圆环
取外圆和内圆的交点,再由索引进行绘制
js
/**
* @description:
* @param {*} x 圆心x坐标
* @param {*} y 圆心y坐标
* @param {*} outerRadius 外环半径
* @param {*} innerRadius 内环半径
* @param {*} n 三角形数量
*/
function createCircleVertex (x: number, y: number, outerRadius: number, innerRadius: number, n: number): { positions: [number]; indices: [number] } {
const positions = []
for (let i = 0; i <= n; i++){
const angle = (i * Math.PI * 2) / n
positions.push(x + innerRadius * Math.sin(angle), y + innerRadius * Math.cos(angle), 255, 0, 0, 1)
positions.push(x + outerRadius * Math.sin(angle), y + outerRadius * Math.cos(angle), 255, 0, 0, 1)
}
const indices = []
for (let i = 0; i < n; i++){
const p0 = i * 2
const p1 = i * 2 + 1
let p2 = (i + 1) * 2 + 1
let p3 = (i + 1) * 2
if (i === n - 1){
p2 = 1
p3 = 0
}
indices.push(p0, p1, p2, p2, p3, p0)
}
return {
positions,
indices
}
}
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0)