three.js是目前國內開發Web3D應用最多的第三方庫,它提供了非常多的3D顯示功能。在使用的時候,雖然three.js 本身做了優化,但是在較大分辨率下,加載較大或者較多模型時會出現,幀率會越低,給人感覺就越卡,因此性能方面的優化對提高視覺體驗有着積極影響。以下是我在項目(vue+threejs)開發結合度娘總結的一些思路,希望能有所幫助。
-
合理執行渲染方法
因為默認情況下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(); -
共享幾何體和材質
不同的網格模型如果可以共享幾何體或材質,最好采用共享的方式,如果兩個網格模型無法共享幾何體或材質,自然不需要共享,比如兩個網格模型的材質顏色不同,這種情況下,一般要分別為網格模型創建一個材質對象
相同或者相似類型的對象生成時多使用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) } -
使用性能檢測插件(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); } -
對粒子群進行轉換,而不是每個粒子
使用THREE.Sprite時,可以更好地控制單個粒子,但是當使用大量的粒子的時候,這個方法的性能會降低,並且會更復雜。此時可以使用THREE.SpriteCloud,可以輕松地管理大量的粒子,進行整體操作,此時對單個粒子的控制能力會減弱。
-
模型的面越少越好,模型過於細致會增加渲染開銷
three場景導入模型時,可以在保證最低清晰度的時候,降低模型的復雜度,面越多,模型越大,加載所需開銷就越大
-
分時加載
調查顯示100ms內的響應能讓用戶感覺非常流暢。50ms是
Nicholas針對JavaScript得出的最佳經驗值,setTimeout 延時25ms,25ms 保證主流瀏覽器都順暢,可以使用類似的方法來優化three.js程序。初始化方法以及渲染方法可以適當添加延時以分散同時渲染的壓力。
當存在多個模型動畫時,根據實際情況可以將多個動畫拆分,再可以對每個動畫requestAnimationFrame分別設置渲染頻率。
-
頁面銷毀時手動調用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() // 刪除材質
-
加載/渲染時間長的添加loading效果
當加載較大模型或者渲染比較復雜的模型時,頁面會有較長時間卡頓,影響用戶體驗。可以添加loading效果,降低用戶等待焦慮。
-
渲染3D的顯卡建議設置為獨立顯卡
在性能和功耗方面,集成顯卡具有一般性能的特點,但基本可以滿足一些日常應用,與獨立顯卡相比,熱功耗低。雖然獨立顯卡的性能很強,但其熱量和功耗都比較高。獨立顯卡在三維性能上優於集成顯卡。
-
修改瀏覽器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 設置為EnabledFirefox瀏覽器:
要想GPU加速文本的功能,不僅僅要下載最新的nightlyBuild火狐(Minefield)之外,還要通過以下方法操作才能開啟該功能:
- 進入about:config配置頁面並搜索gfx.font
- 雙擊gfx.font_rendering.directwrite.enabled打開這項功能;
- 點右鍵新建一個integer,命名為mozilla.widget.render-mode;
- 為該integer賦值為6;
- 重啟瀏覽器。
Edge(win10)瀏覽器:
- 使用 Windows + I 快捷鍵打開「Windows 設置」——導航到「系統」——「顯示」選項頁
- 點擊「多顯示器設置」下的「圖形設置」鏈接,打開「圖形設置」專屬配置頁面
- 在「圖形性能首選項」的下拉列表中選擇「通用應用」——再在「選擇應用」下拉列表中添加 Microsoft Edge 瀏覽器。
- 添加好之后點擊已添加的 Microsoft Edge,再點擊「選項」按鈕
- 在彈出的「圖形規格」選項卡中可以看到當前系統中的所有顯卡,選擇「高性能」並「保存」即可指定 Microsoft Edge 永久使用使用性能最高的 GPU。
- 完成上述操作步驟后,再重新啟動下 Microsoft Edge,它現在就應該會使用 PC 的獨立顯卡進行渲染任務了。
tips:用threejs做大分辨率下的顯示應用時,需要考慮3D渲染的顯卡性能以及顯卡最大分辨率與顯示屏分辨率的對比情況,如果在做了相關優化之后GPU的占用率仍然偏高,頁面動效卡頓,三維效果不理想,甚至出現有時候因GPU超負荷而是電腦卡死的情況,這時候就需要考慮升級顯卡配置了。
