three.js 如何廢置對(duì)象

2023-02-16 17:23 更新

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

幾何體

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

材質(zhì)

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

紋理

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

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

渲染目標(biāo)

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

雜項(xiàng)

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

常見(jiàn)問(wèn)題

為何three.js不能夠自動(dòng)廢置對(duì)象?

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

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

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

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

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

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

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

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

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

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

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

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

WebGL / test / memory

WebGL / test / memory2


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)