three优化篇
清除dispose()
/* 清除不再使用内存模型几何体与材质 防止泄露 */
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;
终极奥义dispose()
function disposeChild(mesh) {
if (mesh instanceof THREE.Mesh) {
if (mesh.geometry?.dispose) {
mesh.geometry.dispose(); //删除几何体
}
if (mesh.material?.dispose) {
mesh.material.dispose(); //删除材质
}
if (mesh.material?.texture?.dispose) {
mesh.material.texture.dispose();
}
}
if (mesh instanceof THREE.Group) {
mesh.clear();
}
if (mesh instanceof THREE.Object3D) {
mesh.clear();
}
}
scene.traverse(item => {
disposeChild(item);
})
THREE.Cache.clear();
scene.clear();
renderer.dispose();
renderer.forceContextLoss();
懒加载优化requestAnimationFrame()
1. 节流渲染
let animId: boolean;
let timeOut: string | number | NodeJS.Timeout | null | undefined = null;
onMounted(() => {
/* 四.渲染循环 */
let render = () => {
stats.update();
if (animId) {
controls.update();
composer.render();
}
/* 动画事件 */
requestAnimationFrame(render);
}
/* 防抖事件 */
const timeRender = ()=>{
animId = true;
if (timeOut) {
clearTimeout(timeOut);
}
timeOut = setTimeout(()=>{
animId = false;
},5000)
}
controls.addEventListener('change', () => {
timeRender()
});
window.addEventListener('mousemove',()=>{
timeRender()
});
/* 每次材质和纹理更新,触发重新渲染,并且在闲置状态会停止渲染 */
THREE.DefaultLoadingManager.onLoad = function () {
timeRender();
};
}
2.判断循环事件
/* 雪 */
if (snowbol) {
snowGroup.children.forEach((sprite: any) => {
sprite.position.y -= t * 50;
if (sprite.position.y < 0) {
sprite.position.y = 600 * Math.random(); // 与y 对应
}
})
}
压缩模型
1.
pnpm i -g gltf-pipeline
public/model/test01.gltf -o 表示需要压缩的模型文件地址
public/model/copy.gltf -d 表示压缩出来的存储位置及名字
gltf-pipeline -i three.gltf -t 保存单独的纹理
pnpm gltf-pipeline -i public/three/shunx2.glb -o /public/three/shunx2plus.glb -d
2.
打开Blender导入模型
导出模型、 点击数据、 勾选压缩
加载压缩模型
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
/* 压缩 */
function loaderDraco() {
const loader = new GLTFLoader();
const draco = new DRACOLoader();
// DRACOLoader依赖examples\jsm\libs\下的 draco 里面多个解压文件
draco.setDecoderPath('./draco/');//根据pubic里面解压文件结构设置
loader.setDRACOLoader(draco);
return loader;
}
export default loaderDraco;
import * as THREE from 'three';
import loaderDraco from '../hooks/DracoLoader';
let group = new THREE.Group();
loaderDraco().load(`/three/测试.glb`, (gltf) => {
group = gltf2.scene
}
删除不必要的面
一个面不会被渲染,是被遮挡的,建模的时候,可以不绘制。比如一个箱子放在地面固定不动,底部平面就可以不绘制。
平面删除多余的顶点
美术三维建模的时候,为了提升渲染性能,首先要注意的就是三角形数量或者说顶点数量。
平面删除多余的顶点
比如一个矩形平面,一般四个顶点就可以了,从视觉上看,多了也没什么用,除非说特殊情况。
曲面控制顶点数量
曲面在不影响光滑程度的情况下,尽量减少面数。
一般来说,距离相机越远,对表面细分程度要求越低,你可以Blender生成一个球体,同样细分程度,距离相机位置不同,然后在threejs测试对比。
Blender模型合并演示
选择多个Mesh:
- 方式1:Shift快捷键+鼠标点击,选择多个模型。
- 方式2:右侧目录树:右键父节点,点击选择层级
- 方式3:选择——选择相连元素——材质 (或者快捷键Shift + L)
合并多个Mesh,转化成一个Mesh:物体——合并 (或者快捷键Ctrl + J)
Blender设置纹理贴图
在Blender中创建一个球体网格模型,然后通过材质,设置一个颜色贴图,实现上面代码同样的效果球体+环境贴图效果。
设置好贴图之后,导出gltf,threejs加载查看设置贴图的模型。
纹理贴图大小(性能优化)
如果纹理贴图像素比较大,一方面会占用渲染的更多硬件资源,另一方面网页从服务器加载图片文件的时间会更长。
共享几何体,减小模型文件
对于外形一样的物体,可以考虑共享几何体。
后处理细分度
根据相机远近动态改变 ssaaRenderPass.sampleLevel 值渲染
参考值
单个场景的所有模型总面数不要超过100万,最低可承受的设备水平为:GTX 1050
控制元素数量,可以有效的降低场景的卡顿
单个场景建议元素数量 小于1000