ThreeJS的性能优化方面

1、网格合并

简介

多数情况下使用组可以很容易地操纵和管理大量网格。但是当对象的数量非常多时,性能就会成为一个瓶颈。使用组,每个对象还是独立的,仍然需要对它们分别进行处理和渲染。通过
THREE.Geometry.merge() 函数,你可以将多个几何体合并起来创建一个联合体。

当我们使用普通组的情况,绘制20000个立方体,帧率在15帧左右,如果我们选择合并以后,再绘制两万,就会发现,我们可以轻松的渲染20000个立方体,而且没有性能的损失。合并的代码如下:

javascript 复制代码
//合并模型,则使用merge方法合并
var geometry = new THREE.Geometry();
//merge方法将两个几何体对象或者Object3D里面的几何体对象合并,(使用对象
的变换)将几何体的顶点,面,UV分别合并.
//THREE.GeometryUtils: .merge() has been moved to Geometry.
Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.
for(var i=0; i<gui.numberOfObjects; i++){
var cube = addCube();
cube.updateMatrix();
geometry.merge(cube.geometry, cube.matrix);
}
scene.add(new THREE.Mesh(geometry, cubeMaterial));

THREE.GeometryUtils.merge() 已经将此方法移动到了 THREE.Geometry 对象的上面了,我们使用 addCube 方法进行立方体的创建,为了确保能正确的定位和旋转合并的 THREE.Geometry 对象,我们不仅向 merge 函数提供 THREE.Geometry 对象,还提供该对象的变换矩阵。当我们将此矩阵添加到 merge 函数后,那么合并的方块将被正确定位。

和组的优缺点对比

缺点: 组能够对每个单独的个体进行操作,而合并网格后则失去对每个对象的单独控制。想要移

动、旋转或缩放某个方块是不可能的。
优点: 性能不会有损失。因为将所有的的网格合并成为了一个,性能将大大的增加。如果需要创建大型的、复杂的几何体。我们还可以从外部资源中创建、加载几何体。

2、尽量重用Material和Geometry

这里以Material和Geometry为例(使用比较频繁)

javascript 复制代码
for (var i = 0; i < 100; i++) {
    var material = new THREE.MeshBasicMaterial();
    var geometry = new THREE.BoxGeometry(10, 10, 10);
    var mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
}

改为

javascript 复制代码
var material = new THREE.MeshBasicMaterial();
var geometry = new THREE.BoxGeometry(10, 10, 10);
for (var i = 0; i < 100; i++) {
    var mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
}

3、尽量使用clone方法

这个的原理其实跟2是一样的

4、重点优化requestAnimationFrame内的方法

我们知道几乎所有的资源都是花费在requestAnimationFrame内的方法,所以我们在需要的时候去执行,如果不需要则不执行。

5、删除模型时,将材质和几何体从内存中清除

使用 remove() 将模型从场景内删除掉,大家会发现内存基本上没有怎么降低。因为几何体和材质还保存在内存当中,我们需要手动调用 dispose() 方法将其从内存中删除。

javascript 复制代码
1. item.geometry.dispose(); //删除几何体
2. item.material.dispose(); //删除材质

6、在循环渲染中避免使用更新

这里的更新指的是当前的几何体、材质、纹理等发生了修改,需要 Three.js 重新更新显存的数据,具体包括:

几何体:

javascript 复制代码
geometry.verticesNeedUpdate = true; //顶点发生了修改
geometry.elementsNeedUpdate = true; //面发生了修改
geometry.morphTargetsNeedUpdate = true; //变形目标发生了修改
geometry.uvsNeedUpdate = true; //uv映射发生了修改
geometry.normalsNeedUpdate = true; //法向发生了修改
geometry.colorsNeedUpdate = true; //顶点颜色发生的修改

材质

javascript 复制代码
material.needsUpdate = true

纹理

javascript 复制代码
texture.needsUpdate = true;

如果它们发生更新,则将其设置为true,Three.js会通过判断,将数据重新传输到显存当中,并将配置项重新修改为false。这是一个很耗运行效率的过程,所以我们尽量只在需要的时候修改,不要放到render()方法当中循环设置。

只在需要的时候渲染

如果在没有操作的时候,让循环一直渲染属于浪费资源,接下来我来带给大家一个只在需要时渲染的方法。

首先在循环渲染中加入一个判断,如果判断值为true时,才可以循环渲染:

javascript 复制代码
var renderEnabled;
function animate() {
if (renderEnabled) {
    renderer.render(scene, camera);
}
    requestAnimationFrame(animate);
}
animate();

然后设置一个延迟器函数,每次调用后,可以将 renderEnabled 设置为 true ,并延迟三秒将其设

置为 false ,这个延迟时间大家可以根据需求来修改:

javascript 复制代码
//调用一次可以渲染三秒
let timeOut = null;
function timeRender() {
//设置为可渲染状态
    renderEnabled = true;
//清除上次的延迟器
if (timeOut) {
    clearTimeout(timeOut);
}
    timeOut = setTimeout(function () {
    renderEnabled = false;
}, 3000);
}

接下来,我们在需要的时候调用这个 timeRender() 方法即可,比如在相机控制器更新后的回调

中:

javascript 复制代码
controls.addEventListener('change', function(){
    timeRender();
});

如果相机位置发生变化,就会触发回调,开启循环渲染,更新页面显示。

如果我们添加了一个模型到场景中,直接调用一下重新渲染即可:

javascript 复制代码
scene.add(mesh);
timeRender();
javascript 复制代码
最后,一个重点问题,就是材质的纹理由于是异步的,我们需要在图片添加完成后,触发回调。好在
Three.js已经考虑到了这一点,Three.js的静态对象THREE.DefaultLoadingManager的onLoad回调会在
每一个纹理图片加载完成后触发回调,依靠它,我们可以在Three.js的每一个内容发生变更后触发重新
渲染,并且在闲置状态会停止渲染。
javascript 复制代码
//每次材质和纹理更新,触发重新渲染
THREE.DefaultLoadingManager.onLoad = function () {
    timeRender();
};
相关推荐
Nan_Shu_6142 天前
学习: Threejs (15)& Threejs (16)
学习·three.js
Charlie_lll2 天前
学习Three.js–材质(Material)
前端·three.js
答案—answer5 天前
开源项目:Three.js3D模型可视化编辑系统
javascript·3d·开源·开源项目·three.js·three.js编辑器
贝格前端工场6 天前
困在像素里:我的可视化大屏项目与前端价值觉醒
前端·three.js
全栈王校长6 天前
Three.js 材质进阶
webgl·three.js
全栈王校长6 天前
Three.js Geometry进阶
webgl·three.js
烛阴7 天前
3D字体TextGeometry
前端·webgl·three.js
全栈王校长7 天前
Three.js 开发快速入门
three.js
全栈王校长7 天前
Three.js 环境搭建与开发初识
three.js
DaMu8 天前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js