一键解决ThreeJS3D场景卡顿问题!轻装3D的几何体实例化与合并

上一篇我们提到过,Three.js模型卡顿,很多时候都可以先从Draco压缩和LOD分级入手,用来解决模型加载慢、首屏卡的问题。

但在实际项目里,还有一种更加常见的情况:模型已经加载出来了,场景也正常显示了,可你一操作镜头就开始掉帧,特别是物体一多,卡顿就更加明显。这个时候,问题往往不是出在加载上,而是运行时的渲染压力太大了。

我自己排查这类问题时,通常会重点看两个方向:实例化渲染和合并几何体。

实例化渲染:重复模型多的时候很有效

当你的场景里有大量重复物体,比如树、路灯、椅子、设备、零件这类,就适合用实例化渲染来做轻量化。

因为这些模型虽然数量很多,但实际上可能只是同一个模型重复摆放了很多次。要是还按普通方式一个个渲染,drawcall分分钟上去,所以场景一复杂就掉帧。

实例化的核心思路,就是让这些重复物体共用同一份几何体和材质,再批量渲染。这样能明显减少渲染提交次数,对运行时性能帮助很直接。

通常来说,使用InstancedMesh可将 Draw Call 从 O (n) 降至 O (1),性能提升 10 倍以上。

javascript 复制代码
import { InstancedMesh, Matrix4 } from 'three';

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial();
const count = 1000; // 1000个立方体

const instancedMesh = new InstancedMesh(geometry, material, count);
const matrix = new Matrix4();

for (let i = 0; i < count; i++) {
  // 设置每个实例的位置、旋转、缩放
  matrix.setPosition(Math.random()*100, Math.random()*100, Math.random()*100);
  instancedMesh.setMatrixAt(i, matrix);
}

scene.add(instancedMesh);
合并几何体:碎模型太多时更有用

还有一种情况是,场景里虽然没有特别多重复的模型,但小物体特别多、特别碎。就好像建筑构件、工业零件、装饰面片之类,单个不复杂,但数量一大,Three.js照样吃不消。

这时候就得用合并几何体了。它的思路也很简单,就是把原本分散的小几何体尽量合并为一个几何体,大幅减少减少场景中的节点数和drawcall,把渲染压力降下来。

javascript 复制代码
import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';

const geometries = [];
for (let i = 0; i < 100; i++) {
  const geometry = new THREE.BoxGeometry();
  geometry.translate(Math.random()*10, Math.random()*10, Math.random()*10);
  geometries.push(geometry);
}

const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries(geometries);
const mesh = new THREE.Mesh(mergedGeometry, material);
scene.add(mesh);
// Draw Call从100降为1
为什么我后来会用轻装3D

要是模型比较少,手动做实例化或者合并其实也能做。但项目一大,你就根本不会想要手动了。

比如哪些模型适合实例化、哪些适合合并、模型改版后要不要重新处理,这些不花费大量的时间根本搞不定。而且很多优化不是前端代码层临时补一补就能彻底解决的,问题根源其实在模型资产本身。

我用轻装3D最直观的感受是,它一键就能把几何体实例化和几何体合并这两步做掉。也就是说,在模型进Three.js之前,就已经把那些容易造成运行时卡顿的问题处理掉了。

通过对重复模型的实例化减少重复渲染压力;通过合并零散小物体降低场景绘制负担。这样用轻装3D处理完的资源就是更适合实时渲染的状态,场景跑起来会轻很多。

小结

如果说Draco和LOD解决的是"模型进来太重"的问题,那实例化和合并几何体解决的就是"场景跑起来太累"的问题。对模型多、场景复杂的项目来说,直接用轻装3D会省事很多,优化效果也更稳定。

相关推荐
用户83134859306981 天前
Vue+Three.js实现PCB电路板3D交互:元器件点击高亮、部件显隐、模型自动旋转
vue.js·webgl·three.js
答案answer1 天前
做了几年 Three.js,我为什么决定自己开发一款3D低代码编辑器
前端·three.js
_lucas6 天前
做了一个glsl在线调试工具
前端·javascript·three.js
云空9 天前
《升级版3D数字沙盘(点击弹窗+第一人称漫游双功能)》
3d·three.js
Strayer9 天前
拓扑管网 3D 可视化大屏demo:科技感(地图 + 拓扑 + 3D 空间)
前端·three.js·数据可视化
用户831348593069811 天前
Vue+Threejs实现人物奔跑场景
vue.js·webgl·three.js
云空12 天前
《Three.js 完整版3D魔方:带贴纸+中心固定+自动求解复原》
前端·javascript·3d·three.js
云空12 天前
《Three.js 可操控3D魔方(键盘转动+打乱+复原)》
javascript·学习·游戏·3d·three.js
云空14 天前
《终极版3D数字沙盘:双视角漫游+建筑点击信息+昼夜一键切换》
3d·three.js
云空14 天前
《Three.js 3D实例大全》
开发语言·javascript·3d·three.js