📦 方案 1: 独立数组(Separate Arrays)
位置和颜色分别存储在两个独立的缓冲区中
// 位置缓冲区
const positions = [x1,y1,z1, x2,y2,z2, ...]
// 颜色缓冲区
const colors = [r1,g1,b1, r2,g2,b2, ...]
优点 代码清晰,易于理解
缺点 需要多次绑定切换
🔀 方案 2: 交错数组(Interleaved Array)
位置和颜色交错存储在同一个缓冲区中
// 交错数据
const data = [
x1,y1,z1, r1,g1,b1, // 顶点1
x2,y2,z2, r2,g2,b2, // 顶点2
...
]
优点 性能更好,缓存友好
缺点 配置稍复杂
❌ 方案 3: 不使用索引(重复顶点)
正方形需要 6 个顶点(2 个三角形 × 3 个顶点)
// 6 个顶点(有重复)
const vertices = [
-0.5,-0.5, 0.5,-0.5, 0.5,0.5, // 三角形1
-0.5,-0.5, 0.5,0.5, -0.5,0.5 // 三角形2
]
顶点数 6 个(重复 2 个)
内存 浪费 33%
✅ 方案 4: 使用索引(Element Array)
正方形只需 4 个顶点 + 6 个索引
// 4 个顶点(无重复)
const vertices = [-0.5,-0.5, 0.5,-0.5, 0.5,0.5, -0.5,0.5]
// 6 个索引
const indices = [0,1,2, 0,2,3]
顶点数 4 个(节省 33%)
内存 更高效
gl.vertexAttribPointer(
index, // attribute 位置
size, // 每个顶点的分量数(1-4)
type, // 数据类型(gl.FLOAT, gl.BYTE 等)
normalized, // 是否归一化(true/false)
stride, // 步长(字节)
offset // 偏移量(字节)
)
stride(步长):从一个顶点的数据开始到下一个顶点的数据开始的字节数
offset(偏移量):当前属性在顶点数据中的起始位置(字节)
独立数组的参数
// 位置缓冲区
gl.vertexAttribPointer(
aPosition,
3, // vec3
gl.FLOAT,
false,
0, // stride = 0(紧密排列)
0 // offset = 0
)
交错数组的参数
// 位置(在交错数组中)
gl.vertexAttribPointer(
aPosition,
3, // vec3
gl.FLOAT,
false,
24, // stride = 6 floats × 4 bytes
0 // offset = 0(位置在前)
)
// 颜色(在交错数组中)
gl.vertexAttribPointer(
aColor,
3, // vec3
gl.FLOAT,
false,
24, // stride = 6 floats × 4 bytes
12 // offset = 3 floats × 4 bytes
)