日月之行,若出其中。星汉灿烂,若出其里。

128 阅读3分钟

three优化篇

1.模型简化

  • 型简化是通过减少多边形数(即顶点和面)来降低模型的复杂度。LOD(Level of Detail,细节层次)
  • Three.js支持LOD功能,能根据相机与模型的距离,自动切换不同细节的模型版本,从而减少渲染负荷。
import { LOD } from 'three';
 
const lod = new LOD();
 
// 设置低细节模型(适合远处显示)
const lowDetailMesh = createLowDetailMesh();
lod.addLevel(lowDetailMesh, 100); // 距离相机100单位时使用低细节模型
 
// 设置中细节模型
const mediumDetailMesh = createMediumDetailMesh();
lod.addLevel(mediumDetailMesh, 50); // 距离相机50单位时使用中细节模型
 
// 设置高细节模型(适合近距离显示)
const highDetailMesh = createHighDetailMesh();
lod.addLevel(highDetailMesh, 0); // 距离相机为0时使用高细节模型
 
scene.add(lod);

2.模型批处理

  • 批处理将多个小模型合并为一个大模型,减少WebGL的绘制调用次数,从而提高性能。在Three.js中,常用的批处理技术包括合并网格(Mesh)、实例化渲染(Instanced Rendering)等。
  • 可以将场景中多个静态对象合并成一个网格,从而减少渲染调用。
import { BufferGeometry, BoxGeometry, Mesh, MeshBasicMaterial, MeshStandardMaterial, Scene } from 'three';
 
// 创建材质和几何体
const material = new MeshStandardMaterial({ color: 0x00ff00 });
const geometry = new BoxGeometry();
 
// 创建多个网格
const meshes = [];
for (let i = 0; i < 10; i++) {
  const mesh = new Mesh(geometry, material);
  mesh.position.set(i * 2, 0, 0);
  meshes.push(mesh);
}
 
// 合并网格
const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries(meshes.map(m => m.geometry), true);
const mergedMesh = new Mesh(mergedGeometry, material);
scene.add(mergedMesh);

实例化渲染:使用InstancedMesh可以实现一次性渲染多个相同的网格,提高渲染效率。

import { InstancedMesh, BoxGeometry, MeshBasicMaterial, Matrix4 } from 'three';
 
const geometry = new BoxGeometry();
const material = new MeshBasicMaterial({ color: 0x00ff00 });
const count = 100;
 
const instancedMesh = new InstancedMesh(geometry, material, count);
 
for (let i = 0; i < count; i++) {
  const matrix = new Matrix4();
  matrix.setPosition(i % 10, Math.floor(i / 10), 0);  // 设置位置
  instancedMesh.setMatrixAt(i, matrix);
}
 
scene.add(instancedMesh);

硬件加速与性能优化技巧

硬件加速和性能优化是确保Three.js应用在多种设备上流畅运行的关键。优化渲染管道和减少GPU负荷能有效提高应用的响应速度。

  • 使用帧率限制和动态分辨率。通过调整渲染器的更新时间,控制最大帧率。
let lastRenderTime = 0;
const maxFPS = 30;
 
function animate(time) {
  const delta = time - lastRenderTime;
  if (delta > 1000 / maxFPS) {
    renderer.render(scene, camera);
    lastRenderTime = time;
  }
  requestAnimationFrame(animate);
}
animate(0);

动态分辨率:动态调整渲染分辨率,在保持画质的同时降低渲染负担。Three.js中可以通过调整渲染器的setPixelRatio来实现。

renderer.setPixelRatio(window.devicePixelRatio > 1 ? 1.5 : 1);

场景剔除和遮挡剔除

  • 场景剔除:Three.js中的场景剔除技术会自动隐藏相机视野外的对象。可以进一步使用分区剔除技术来优化大型场景。
  • 遮挡剔除:在一些场景中,对被完全遮挡的物体进行剔除,可以减轻渲染负担。

清除不必要场景模型

/* 清除不再使用内存模型几何体与材质 防止泄露 */
mesh.remove()
1.
mesh.traverse((obj:any)=> {
    if (obj.type === 'Mesh') {
      obj.geometry.dispose();
      obj.material.dispose();
    }
})

2.
model.traverse((obj) => {
    if (!obj.isMesh) return;
    obj.geometry.dispose();
    obj.material.dispose();
});
model = null;

节流渲染 requestAnimationFrame()

-面板超出一定时间停止渲染、鼠标事件触发重新渲染

1. 节流渲染
let timeOut;
let render = () => {
    stats.update();
    if (timeOut) {
      controls.update();
      composer.render();
    }
    /* 动画事件 */
    requestAnimationFrame(render);
};render()