多实例渲染
一个方块被四百个实例复用。顶点属性只上传一次,每个实例读自己的偏移与颜色, 绘制调用仍然只有一次。
说明
顶点着色器同时接收顶点属性与实例属性:positions 逐顶点步进,
instanceOffsets 与 instanceColors 逐实例步进。
着色器里一次乘法就把单位方块放到实例位置,GPU 对每个实例重复这段计算。
滑块只改 instanceCount。缓冲区按最大数量预分配,
调小只是少画一些实例,不需要重新上传数据。
| 项目 | 取值 | 说明 |
|---|---|---|
| 顶点数量 | 6 | 两个三角形组成的单位方块 |
| 实例数量 | 20 – 400 | 由滑块控制,默认 400 |
| 绘制调用 | 1 | 与实例数量无关 |
| 顶点步进 | vertex | positions |
| 实例步进 | instance | instanceOffsets、instanceColors |
| 属性格式 | float32x3 | 三组属性一致 |
实例属性怎么声明
const model = new Model(device, {
topology: 'triangle-list',
vertexCount: 6,
instanceCount: 400,
attributes: {
positions: quadBuffer,
instanceOffsets: offsetBuffer,
instanceColors: tintBuffer
},
bufferLayout: [
{ name: 'positions', stepMode: 'vertex', format: 'float32x3' },
{ name: 'instanceOffsets', stepMode: 'instance', format: 'float32x3' },
{ name: 'instanceColors', stepMode: 'instance', format: 'float32x3' }
],
vs: vsSource,
fs: fsSource
});
instanceCount 大于 0 时模型自动按实例化绘制。
stepMode 必须显式写成 instance,
否则这些缓冲区会被当成逐顶点数据,第一个实例之外的位移就读不到了。
着色器里的分工
in vec3 positions;
in vec3 instanceOffsets;
in vec3 instanceColors;
out vec3 vColor;
void main() {
vColor = instanceColors;
vec3 p = positions * 0.038 + instanceOffsets;
gl_Position = vec4(p, 1.0);
}
顶点属性提供形状,实例属性提供摆放与配色。
想再加逐实例的旋转或缩放,加一条 stepMode: 'instance' 的缓冲区即可,
不需要新增绘制调用。
与逐次绘制相比
逐个绘制时,每次调用都要重设属性、走一遍驱动校验;实例化把这些开销摊到一次调用上。 四百个实例的差距不明显,进入几万个实例后通常是数量级的差别。 代价是实例之间只能靠属性区分,无法在两次绘制之间改变管线状态。
GIS 里的对应场景
点要素是最典型的用例:单位圆或图标作为顶点数据,每个点的坐标、颜色、大小作为实例属性。 百万级 POI 之所以能在一帧里画完,靠的就是这条路径。
实例数据要按最大数量预分配。 每帧重建缓冲区会把上传开销拉回逐次绘制的量级。 固定容量、只改绘制数量,才能保住实例化的收益。