经纬志
首页 / three.js / 使用示例

性能对比

同样的五千个立方体、同样的位置与朝向,分别用五千个 Mesh 与一个 InstancedMesh 绘制。 绘制调用从五千降到一次,帧率与构建耗时会实时显示。

three.js 0.160.0 · 更新 2026-10-27
源码与运行效果
运行效果

说明

两种模式共用同一份位置、朝向与颜色数据。实例化版本把这些数据写进 一个实例矩阵缓冲与一个实例颜色缓冲;独立网格版本创建五千个 Mesh,每个都有自己的材质实例。

切换模式时观察三个数字:绘制调用、三角面、帧率。绘制调用会从个位数跳到五千以上, 三角面数量不变。这个对比能说明「对象数量」与「几何复杂度」是两个不同的瓶颈。

指标实例化独立网格结论
绘制调用15000差距最大的地方
三角面6000060000几何量相同
材质数量15000独立网格需要逐对象克隆材质
构建耗时几十毫秒数百毫秒创建对象本身有成本
单对象改色改实例颜色直接改材质实例化需要用 setColorAt

绘制调用为什么贵

每一次绘制调用都要在 CPU 侧切换管线状态、绑定缓冲、提交命令。 单次开销是微秒级,看起来不多,但五千次就是几十毫秒,足够吃掉一帧。 把大量同形状对象合并成一次调用,是最直接有效的优化。

需要注意的是,实例化并不减少顶点与像素工作量。五千个立方体占满屏幕时, 瓶颈会转移到填充率,帧率未必有改善。它解决的是 CPU 侧的调用开销。

什么情况适合实例化

  • 几何体完全一致,只有位置、旋转、缩放或颜色不同,例如树木、路灯、井盖。
  • 数量在数百以上,替换为实例化能明显降低绘制调用。
  • 不需要每个对象独立的材质结构(不同贴图、不同透明模式)。

如果每个对象都要不同的贴图或着色器,实例化就不适用。 此时更合适的是合并静态几何体,或按材质分批实例化。

读取统计信息

renderer.render(scene, camera);

console.log(renderer.info.render.calls);     // 本帧绘制调用
console.log(renderer.info.render.triangles); // 本帧三角面
console.log(renderer.info.memory.geometries); // 常驻几何体数量
console.log(renderer.info.memory.textures);   // 常驻纹理数量

info 每次渲染开始时重置,所以必须在渲染之后立刻读取。 排查显存泄漏时,观察 memory.geometries 与 memory.textures 是否持续增长,比只看内存占用更准确。

先量再优化。绘制调用、三角面、帧时间三者指向不同的问题。 不区分地「减少对象」或「减面」,经常优化了不是瓶颈的那一项, 复杂度上去了,帧率却几乎没变。