three.js优化

Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。

three.js 性能优化方面,整理一下常用的优化方法或者方向,供大家一个优化思考的方向

尽量重用Material和Geometry

分时加载

分时加载算法(大数组)

调查显示100ms内的响应能让用户感觉非常流畅。50ms是 Nicholas 针对 JavaScript 得出的最佳经验值。

setTimeout 延时25ms,25ms 保证主流浏览器都顺畅。

可以使用类似的方法来优化three.js程序。

    function timedChunk(items, process, context, callback){
    
        var todo = items.concat();   
    
        setTimeout(function(){
        
            var start = +new Date();
        
            do {
                 process.call(context, todo.shift());
            } while (todo.length > 0 && (+new Date() - start < 50));
 
            if (todo.length > 0){
                setTimeout(arguments.callee, 25);
            } else {
                callback(items);
            }
        }, 25);
    };
 

 物体的清理

不销毁模型和材质只是单纯的remove的话还是会内存泄漏的.

    scene.remove(cube)
    cube.geometry.dispose()
    cube.matertial.diapose()

合理执行渲染方法.render()

.render()方法每次执行都需要调用大量的CPU、GPU等硬件资源,所以为了提高渲染性能,可以考虑尽量减少.render()的执行次数。

如果场景默认是静态的,没有动画,比如展示一个产品、建筑或机械零件的三维模型,只需要在鼠标旋转缩放三维模型,触发.render()执行即可,在没有发生鼠标事件的时候,可以不执行.render()

对一些有动画的场景,可以适当控制requestAnimationFrame()函数周期

性执行渲染的次数,比如把默认60FBS设置为30FBS。

渲染帧率的优化,其实就是合理调用 render

帧率优化的思路主要是需要时才渲染,无操作时不调用render()。什么时候需要调用渲染呢?主要包含以下情况:

scene中object的增、删、改
object被选中、反选
相机位置、观察点变化
渲染区域大小变化

于是我们需要注意哪些操作会触发这些变化,主要有以下操作:

scene.add/remove方法被调用 (当模型被加载、移除等)
object material的变化,位置、缩放、旋转、透明度等变化
OrbitControls的的变化
camera的 'change'事件
鼠标的 mousedown/mouseup/mousemove等事件
键盘的w/a/s/d/up/down/left/right arrow等

对于大多数一般处于静态的三维场景,可以不一直周期性执行threejs渲染器方法.render(),根据需要执行.render(),比如通过鼠标旋转模型,就通过鼠标事件触发.render()执行,或者在某个时间段出现动画,就在这个时间段周期性执行.render(),过了这个时间段,就恢复原来状态。

比如鼠标控件OrbitControls,当通过OrbitControls控件旋转缩放三维模型的时候,触发渲染器进行渲染。

    // 渲染函数
    function render() {
      renderer.render(scene, camera);
    }
    render();
    var controls = new THREE.OrbitControls(camera);
    //监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
    controls.addEventListener('change', render);

减少没必要执行的代码在周期性渲染函数中的执行

threejs会通过requestAnimationFrame()周期性执行一个渲染函数render(),在渲染函数中除了渲染器.render()方法,其它的尽量放在渲染函数外面,如果必须放在里面的,可以加上if判断尽量加上,不要每次执行render函数的时候,每次都执行没必要执行的代码。

InstancedMesh

在新的threejs版本中,新增加了几个很有意思的Instance类,这里重点挑InstancedMesh来说。InstancedMesh与使用一个geometry共享创建出Mesh是不一样的,InstancedMesh最终达到的效果是一次Drawcall,而共享geometry创建出来的Mesh并无此效果,效率跟不共享创建Mesh渲染性能上没有太大区别,只是可能会省点内存。

InstancedMesh是R110之后出现,有兴趣的可以试试

 

待更。。。

posted @ 2023-02-14 21:40    阅读(311)  评论(0编辑  收藏  举报