摘要
本文系统梳理了 Three.js 性能优化的核心策略,强调优化是一项涵盖资源、渲染与代码的系统性工程。在资源加载层面,文章建议通过建模工具减少多边形数量以实现模型轻量化,采用压缩格式与纹理图集(Atlas)降低显存与切换开销,并利用 LoadingManager 实现资源的异步与按需加载。在渲染层面,重点介绍了利用 InstancedMesh 实现批量渲染以大幅减少绘制调用(Draw Call),通过 LOD(层级细节)技术根据相机距离动态切换模型精度,以及合理运用视锥体裁剪剔除视野外物体。在代码层面,文章建议使用 BufferGeometry、合并相似材质网格,并严格避免在动画循环中创建新对象以减轻垃圾回收压力,从而全面提升 3D 场景的运行帧率与流畅度。
目录
[1. 模型轻量化](#1. 模型轻量化)
[2. 纹理优化](#2. 纹理优化)
[3. 异步加载](#3. 异步加载)
[1. 使用 InstancedMesh 批量渲染](#1. 使用 InstancedMesh 批量渲染)
[2. LOD 层级细节](#2. LOD 层级细节)
[3. 视锥体裁剪](#3. 视锥体裁剪)
一、为什么要优化性能
在复杂 3D 场景中,性能问题往往成为制约体验的关键因素。Three.js 性能优化是一个系统性工程,需要从资源、渲染、代码和硬件四个层面综合施策。
二、资源加载优化
1. 模型轻量化
模型文件过大是性能瓶颈的常见原因。建议使用 Blender 等工具减少多边形数量------将高精度模型从 10 万面降低至 2 万面,帧率可提升 30% 以上。
2. 纹理优化
-
纹理压缩:采用 ASTC、ETC2 格式压缩纹理,减少显存占用
-
纹理合并:将多个小纹理合并为一张大图(Atlas),可降低 90% 的纹理切换开销
3. 异步加载
使用 LoadingManager 监控加载进度,优先加载首屏可见资源:
javascript
const manager = new THREE.LoadingManager();
manager.onProgress = (url, loaded, total) => {
console.log(`加载中:${loaded}/${total}`);
};
const loader = new THREE.TextureLoader(manager);
三、渲染优化
1. 使用 InstancedMesh 批量渲染
实例化允许同时渲染共享相同几何体和材质的多个对象,通过单次绘制调用即可完成:
javascript
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);
for (let i = 0; i < 1000; i++) {
const matrix = new THREE.Matrix4();
matrix.setPosition(
Math.random() * 100 - 50,
Math.random() * 100 - 50,
Math.random() * 100 - 50
);
instancedMesh.setMatrixAt(i, matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true;
scene.add(instancedMesh);
使用 InstancedMesh 后,1000 个物体的绘制调用从 1000 次减少到 1 次。
2. LOD 层级细节
根据相机距离动态切换模型精度:
javascript
const lod = new THREE.LOD();
const highRes = new THREE.Mesh(highResGeometry, material);
const lowRes = new THREE.Mesh(lowResGeometry, material);
lod.addLevel(highRes, 0); // 近距离使用高精度
lod.addLevel(lowRes, 50); // 50单位后切换低精度
scene.add(lod);
3. 视锥体裁剪
Three.js 默认启用视锥体裁剪,对于静态对象可手动控制:
javascript
mesh.frustumCulled = true; // 默认开启,自动裁剪视野外物体
四、代码优化建议
-
使用
BufferGeometry替代已废弃的Geometry -
合并相似材质的网格,减少 draw call
-
在动画循环中避免创建新对象,减少垃圾回收压力