three.js 如何廢置對象

2023-02-16 17:23 更新

為了提高性能,并避免應(yīng)用程序中的內(nèi)存泄露,一個重要的方面是廢置未使用的類庫實體。 每當(dāng)你創(chuàng)建一個three.js中的實例時,都會分配一定數(shù)量的內(nèi)存。然而,three.js會創(chuàng)建在渲染中所必需的特定對象, 例如幾何體或材質(zhì),以及與WebGL相關(guān)的實體,例如buffers或著色器程序。 非常值得注意的是,這些對象并不會被自動釋放;相反,應(yīng)用程序必須使用特殊的API來釋放這些資源。 本指南簡要概述了這一API是如何使用的,以及哪些對象是和這一環(huán)境相關(guān)的。

幾何體

幾何體常用來表示定義為屬性集合的頂點(diǎn)信息,three.js在內(nèi)部為每一個屬性創(chuàng)建一個WebGLBuffer類型的對象。 這些實體僅有在調(diào)用BufferGeometry.dispose()的時候才會被刪除。 如果應(yīng)用程序中的幾何體已廢棄,請執(zhí)行該方法以釋放所有相關(guān)資源。

材質(zhì)

材質(zhì)定義了物體將如何被渲染。three.js使用材質(zhì)所定義的信息來構(gòu)造一個著色器程序,以用于渲染。 著色器程序只有在相應(yīng)材質(zhì)被廢置后才能被刪除。由于性能的原因,three.js盡可能嘗試復(fù)用已存在的著色器程序。 因此,著色器程序只有在所有相關(guān)材質(zhì)被廢置后才被刪除。 你可以通過執(zhí)行Material.dispose()方法來廢置材質(zhì)。

紋理

對材質(zhì)的廢置不會對紋理造成影響。它們是分離的,因此一個紋理可以同時被多個材質(zhì)所使用。 每當(dāng)你創(chuàng)建一個Texture實例的時候,three.js在內(nèi)部會創(chuàng)建一個WebGLTexture實例。 和buffer相似,該對象只能通過調(diào)用Texture.dispose()來刪除。

如果您使用 ImageBitmap 作為紋理的數(shù)據(jù)源,則必須在應(yīng)用程序級別調(diào)用 ImageBitmap.close() 以處理所有 CPU 端資源。在 Texture.dispose() 中自動調(diào)用 ImageBitmap.close() 是不可能的,因為圖像位圖變得不可用,并且引擎無法知道圖像位圖是否在別處使用。

渲染目標(biāo)

WebGLRenderTarget類型的對象不僅分配了WebGLTexture的實例, 還分配了WebGLFramebufferWebGLRenderbuffer來實現(xiàn)自定義渲染目標(biāo)。 這些對象僅能通過執(zhí)行WebGLRenderTarget.dispose()來解除分配。

雜項

有一些來自examples目錄的類,例如控制器或者后期處理過程,提供了dispose()方法以用于移除內(nèi)部事件監(jiān)聽器或渲染目標(biāo)。 通常來講,非常建議查閱類的API或者文檔,并注意dispose()函數(shù)。如果該函數(shù)存在的話,你應(yīng)當(dāng)在清理時使用它。

常見問題

為何three.js不能夠自動廢置對象?

這一問題在社區(qū)中多次被問到,因此澄清這件事情是十分有必要的。事實是,three.js并不知道用戶所創(chuàng)建的實體(例如幾何體或者材質(zhì))的生命周期或作用范圍,這些是應(yīng)用程序的責(zé)任。 比如說,即使一個材質(zhì)當(dāng)前沒有被用于渲染,但它也可能是下一幀所必需的。 因此,如果應(yīng)用程序決定某個對象可以被刪除,則它必須通過調(diào)用對應(yīng)的dispose()方法來通知引擎。

將一個mesh(網(wǎng)格)從場景中移除,是否也會廢置它的geometry(幾何體)和material(材質(zhì))?

并不會,你必須通過dispose()來明確地廢置geometry(幾何體)或material(材質(zhì))。 請記住,geometry(幾何體)或material(材質(zhì))可以在3D物體之間(例如mesh(網(wǎng)格))被共享。

three.js是否會提供被緩存對象數(shù)量的相關(guān)信息?

是的,可以評估WebGLRenderer.info —— 渲染器中的一個特殊屬性,具有一系列關(guān)于顯存和渲染過程的統(tǒng)計信息。 除此之外,它還告訴你有多少紋理、幾何體和著色器程序在內(nèi)部存儲。 如果你在你的應(yīng)用程序中注意到了性能問題,一個較好的方法便是調(diào)試該屬性,以便輕松識別內(nèi)存泄漏。

當(dāng)你在紋理還沒有被加載時,在紋理上調(diào)用dispose(),會發(fā)生什么?

對于紋理的內(nèi)部資源僅在圖像完全被加載后才會分配。如果你在圖像被加載之前廢置紋理,什么都不會發(fā)生。 沒有資源被分配,因此也沒有必要進(jìn)行清理。

當(dāng)我在調(diào)用dispose()之后,使用相應(yīng)的對象會發(fā)生什么?

被刪除掉的內(nèi)部資源會被引擎重新創(chuàng)建,因此不會有運(yùn)行時錯誤發(fā)生,但你可能會注意到這會對當(dāng)前幀的性能有一些影響,特別是當(dāng)著色器程序被編譯的時候。

我如何在我的應(yīng)用程序中管理three.js中的對象?我如何知道什么時候該廢置事物?

一般來說,對此并沒有明確的建議。調(diào)用dispose()什么時候合適,很大程度上取決于具體的用例。 必須指出的是,沒有必要總是廢置對象。一個較好的例子便是一個由多個關(guān)卡所組成的游戲。使用到對象廢置的地方就是當(dāng)切換關(guān)卡的時候。 應(yīng)用程序可以通過較老的場景,并廢置所有過時的材質(zhì)、幾何體和紋理貼圖。 正如在前面的章節(jié)中所提到,如果你廢置一個仍然在使用的對象,并不會導(dǎo)致運(yùn)行時錯誤??赡馨l(fā)生的最糟糕的事情便是單幀的性能會下降。

演示dispose()使用方法的示例

WebGL / test / memory

WebGL / test / memory2


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號