three.js是目前国内开发Web3D应用最多的第三方库,它提供了非常多的3D显示功能。在使用的时候,虽然three.js 本身做了优化,但是在较大分辨率下,加载较大或者较多模型时会出现,帧率会越低,给人感觉就越卡,因此性能方面的优化对提高视觉体验有着积极影响。以下是我在项目(vue+threejs)开发结合度娘总结的一些思路,希望能有所帮助。

  1. 合理执行渲染方法

    因为默认情况下requestAnimationFrame()每秒执行60次,如果在里面加个for循环,代码效率就会严重影响,同时还要减少浮点计算,系统对浮点计算开支比较大,尽量写成小数乘法。

    在一些特定的应用中没有必要保持Threejs渲染频率为60FPS,那么可以通过Threejs渲染时间判断来控制Threejs渲染频率,比如设置为30FPS。

    下面代码通过时钟对象.Clock.getDelta()方法获得threejs两帧渲染时间间隔,然后通过时间判断来控制渲染器渲染方法.render()每秒执行次数:

    // 创建一个时钟对象Clock
    var clock = new THREE.Clock();
    // 设置渲染频率为30FBS,也就是每秒调用渲染器render方法大约30次
    var FPS = 30;
    var renderT = 1 / FPS; //单位秒  间隔多长时间渲染渲染一次
    // 声明一个变量表示render()函数被多次调用累积时间
    // 如果执行一次renderer.render,timeS重新置0
    var timeS = 0;
    function render() {
      requestAnimationFrame(render);
      //.getDelta()方法获得两帧的时间间隔
      var T = clock.getDelta();
      timeS = timeS + T;
      // requestAnimationFrame默认调用render函数60次,通过时间判断,降低renderer.render执行频率
      if (timeS > renderT) {
        // 控制台查看渲染器渲染方法的调用周期,也就是间隔时间是多少
        console.log(`调用.render时间间隔`,timeS*1000+'毫秒');
        renderer.render(scene, camera); //执行渲染操作
        ...
        //renderer.render每执行一次,timeS置0
        timeS = 0;
      }
    }
    render();
    
  2. 共享几何体和材质

    不同的网格模型如果可以共享几何体或材质,最好采用共享的方式,如果两个网格模型无法共享几何体或材质,自然不需要共享,比如两个网格模型的材质颜色不同,这种情况下,一般要分别为网格模型创建一个材质对象

    相同或者相似类型的对象生成时多使用clone()方法,例如生成多个类似的立方体,推荐使用group,结合clone()方法,代码如下

    const group = new THREE.Group()
    const bar = new THREE.Mesh(barGeo, material)
    bar.scale.set(0.3, 0.3, 0.3)
    for (let i = 0; i < 80; i++) {
        const cBar = bar.clone()
        group.add(cBar)
    }
    
  3. 使用性能检测插件(stats.js)监测页面性能
    // 引入stats.js
    import Stats from 'three/examples/js/libs/stats.min.js'
    const stats = new Stats()
    // 设置stats样式
    stats.dom.style.position = 'absolute';
    stats.dom.style.top = '0px';
    document.body.appendChild(stats.dom);
    

    在渲染函数中需要添加如下代码:

    function Animate() {
        requestAnimationFrame(Animate);
        Render();
    }
    function Render() {
    	// 更新stats
        stats.update();
        render.render(scene,camera);
    }
    
  4. 对粒子群进行转换,而不是每个粒子

    使用THREE.Sprite时,可以更好地控制单个粒子,但是当使用大量的粒子的时候,这个方法的性能会降低,并且会更复杂。此时可以使用THREE.SpriteCloud,可以轻松地管理大量的粒子,进行整体操作,此时对单个粒子的控制能力会减弱。

  5. 模型的面越少越好,模型过于细致会增加渲染开销

    three场景导入模型时,可以在保证最低清晰度的时候,降低模型的复杂度,面越多,模型越大,加载所需开销就越大

  6. 分时加载

    调查显示100ms内的响应能让用户感觉非常流畅。50ms是 Nicholas 针对 JavaScript 得出的最佳经验值,setTimeout 延时25ms,25ms 保证主流浏览器都顺畅,可以使用类似的方法来优化three.js程序。

    初始化方法以及渲染方法可以适当添加延时以分散同时渲染的压力。

    当存在多个模型动画时,根据实际情况可以将多个动画拆分,再可以对每个动画requestAnimationFrame分别设置渲染频率。

  7. 页面销毁时手动调用dispose方法,清除延时
    beforeDestroy () {
    	clearTimeout()
    	try {
    		this.scene.clear()
    		this.renderer.dispose()
    		this.renderer.forceContextLoss()
    		this.renderer.content = null
    		// cancelAnimationFrame(animationID) // 去除animationFrame
    		const gl = this.renderer.domElement.getContext('webgl')
    		gl && gl.getExtension('WEBGL_lose_context').loseContext()
    	} catch (e) {
    		console.log(e)
    	}
    }
    

    一个网格模型Mesh是包含几何体geometry和材质对象Material的,几何体geometry本质上就是顶点数据,Three.js通过WebGL渲染器解析几何体的时候会调用WebGL API创建顶点缓冲区来存储顶点数据。

    如果仅仅执行scene.remove(Mesh)只是把网格模型从场景对象的.children属性中删除,解析网格模型Mesh几何体的顶点数据通过WebGL API创建的顶点缓冲区占用的内存并不会释放。

    从内存中删除对象或者删除几何体时不要忘记调用以下方法,因为可能导致内存泄漏

    geometry.dispose() // 删除几何体

    material.dispose() // 删除材质

  8. 加载/渲染时间长的添加loading效果

    当加载较大模型或者渲染比较复杂的模型时,页面会有较长时间卡顿,影响用户体验。可以添加loading效果,降低用户等待焦虑。

  9. 渲染3D的显卡建议设置为独立显卡

    在性能和功耗方面,集成显卡具有一般性能的特点,但基本可以满足一些日常应用,与独立显卡相比,热功耗低。虽然独立显卡的性能很强,但其热量和功耗都比较高。独立显卡在三维性能上优于集成显卡。

  10. 修改浏览器GUP加速相关设置
    Chrome浏览器:
    chrome://flags/#enable-gpu-rasterization   GPU rasterization  设置为Enabled
    chrome://flags/#ignore-gpu-blocklist  Override software rendering list   设置为Enabled
    chrome://flags/#enable-zero-copy    Zero-copy rasterizer   设置为Enabled
    
    Firefox浏览器:

    要想GPU加速文本的功能,不仅仅要下载最新的nightlyBuild火狐(Minefield)之外,还要通过以下方法操作才能开启该功能:

    1. 进入about:config配置页面并搜索gfx.font
    2. 双击gfx.font_rendering.directwrite.enabled打开这项功能;
    3. 点右键新建一个integer,命名为mozilla.widget.render-mode;
    4. 为该integer赋值为6;
    5. 重启浏览器。
    Edge(win10)浏览器:
    1. 使用 Windows + I 快捷键打开「Windows 设置」——导航到「系统」——「显示」选项页
    2. 点击「多显示器设置」下的「图形设置」链接,打开「图形设置」专属配置页面
    3. 在「图形性能首选项」的下拉列表中选择「通用应用」——再在「选择应用」下拉列表中添加 Microsoft Edge 浏览器。
    4. 添加好之后点击已添加的 Microsoft Edge,再点击「选项」按钮
    5. 在弹出的「图形规格」选项卡中可以看到当前系统中的所有显卡,选择「高性能」并「保存」即可指定 Microsoft Edge 永久使用使用性能最高的 GPU。
    6. 完成上述操作步骤后,再重新启动下 Microsoft Edge,它现在就应该会使用 PC 的独立显卡进行渲染任务了。

tips:用threejs做大分辨率下的显示应用时,需要考虑3D渲染的显卡性能以及显卡最大分辨率与显示屏分辨率的对比情况,如果在做了相关优化之后GPU的占用率仍然偏高,页面动效卡顿,三维效果不理想,甚至出现有时候因GPU超负荷而是电脑卡死的情况,这时候就需要考虑升级显卡配置了。

Logo

前往低代码交流专区

更多推荐