ThreeJS的性能优化方面

网友投稿 458 2022-09-20

ThreeJS的性能优化方面

1、网格合并

简介

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

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

//合并模型,则使用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

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

和组的优缺点对比

缺点:组能够对每个单独的个体进行操作,而合并网格后则失去对每个对象的单独控制。想要移 动、旋转或缩放某个方块是不可能的。优点:性能不会有损失。因为将所有的的网格合并成为了一个,性能将大大的增加。如果需要创建大型的、复杂的几何体。我们还可以从外部资源中创建、加载几何体。

2、尽量重用Material和Geometry

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

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);}

改为

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() 方法将其从内存中删除。

1. item.geometry.dispose(); //删除几何体2. item.material.dispose(); //删除材质

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

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

几何体:

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

材质

material.needsUpdate = true

纹理

texture.needsUpdate = true;

如果它们发生更新,则将其设置为true,Three.js会通过判断,将数据重新传输到显存当中,并将配置项重新修改为false。这是一个很耗运行效率的过程,所以我们尽量只在需要的时候修改,不要放到render()方法当中循环设置。 只在需要的时候渲染 如果在没有操作的时候,让循环一直渲染属于浪费资源,接下来我来带给大家一个只在需要时渲染的方法。 首先在循环渲染中加入一个判断,如果判断值为true时,才可以循环渲染:

var renderEnabled;function animate() {if (renderEnabled) { renderer.render(scene, camera);} requestAnimationFrame(animate);}animate();

然后设置一个延迟器函数,每次调用后,可以将 renderEnabled 设置为 true ,并延迟三秒将其设 置为 false ,这个延迟时间大家可以根据需求来修改:

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

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

controls.addEventListener('change', function(){ timeRender();});

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

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

scene.add(mesh);timeRender();

最后,一个重点问题,就是材质的纹理由于是异步的,我们需要在图片添加完成后,触发回调。好在Three.js已经考虑到了这一点,Three.js的静态对象THREE.DefaultLoadingManager的onLoad回调会在每一个纹理图片加载完成后触发回调,依靠它,我们可以在Three.js的每一个内容发生变更后触发重新渲染,并且在闲置状态会停止渲染。

//每次材质和纹理更新,触发重新渲染THREE.DefaultLoadingManager.onLoad = function () { timeRender();};

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:五、线上环境安装配置实操(jdk-tomcat-maven-vsftpd-nginx)
下一篇:广告文案:2020,大品牌,弱传播!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~