Unity性能優化

SetPass calls表示在當前攝像機的渲染過程中,Unity切換著色器通道(Shader Pass)來渲染游戲對象的次數。一個著色器(Shader)可以包含多個著色器通道,每個著色器通道可以通過不同的方式來渲染游戲對象。但每次切換著色器通道都會消耗一定的性能,應盡量避免這項數據過大。

大地圖的分塊加載。場景管理器,子場景管理器,整個大地圖是一個數組,里面存著所有的子場景,創建子場景。最多加載四個子場景。

不規則地圖的解封處理,美術在開發大地圖時的工作流程。

玩家的位置和地圖中心點的位置,小于某個值(10),就把地圖加載出來,小于某個值(10)卸載。

場景模型優化,CPU,GPU。CPU從內存讀取數據(比如模型)發出指令,從RAM內存到顯卡的AGP端口。顯卡把數據放進顯存。顯卡的運算單元叫GPU。最后送到顯示器。

硬件機理,

優化總體原則,

場景優化:

??????? 對始終靜止不動的游戲對象使用靜態合批技術。
??????? 盡量使用同一個材質,以便使用動態合批技術。
??????? 使用GPU Instancing技術。
??????? 使用遮擋剔除。
??????? 進入游戲后的第一個場景要盡量簡單,這樣可以減少游戲的啟動時間。可以先進一個簡單的場景,再進行異步加載,之后再進入游戲的主要的場景。
??????? 盡量避免Hierarchy窗口的層級結構過深。例如一個物體有很多個子物體,這些子物體又有其它子物體,這些子物體又有其它子物體,繼續這樣下去就會導致層級結構過深,我們應盡量減少這種情況。
??????? Edit——Project Settings——Quality,可以對不同平臺中游戲的品質進行設置。
??????? 如果使用了后期處理技術,例如Post Processing等插件,調整屏幕效果的屬性,不要使用太絢麗的特效,可以優化性能。
??????? 要優化Terrain地形,可以使用Unity資源商店的插件,例如Terrain To Mesh插件可以把地形烘焙成網格。
??????? 場景要盡可能簡單,盡量多使用預制體,用代碼動態創建它們出來,并管理它們。

合批的材質如果想修改,修改共享材質,Render,shareMaterial來保證材質共享狀態。

一、靜態批處理(房子建筑山)

定點數據和三角形索引(三角形構成)數據。

對于始終靜止不動的物體使用靜態合批后,CPU會把它們合并為一個批次發送給GPU處理,這樣可以減少Draw Call帶來的性能消耗,從而提升游戲性能。

要使用靜態合批,必須確保Edit——Project Settings——Player——Other Settings——Static Batching是勾選的。

把一個物體設置為靜態的方法:
選中該物體,點擊在Inspector窗口右上角的Static右方的下拉菜單,選擇Batching Static

使用靜態合批雖然可以提升游戲性能,但是設置為靜態的物體在整個游戲中就不能再運動了,強行使它們運動會出問題。

房屋樹木石頭

二、動態合批

動態合批默認是由Unity自動完成。可以在Edit——Project Settings——Player——Other Settings——Dynamic Batching查看。默認Dynamic Batching是勾選的,當條件滿足時,Unity會自動對使用了相同材質(Material)的物體進行動態合批。如果取消勾選,則不會進行動態合批。

1、Unity不能對包含超過900個頂點屬性和225個頂點的網格應用動態批處理。這是因為網格的動態批處理對每個頂點都有開銷。例如,如果你的著色器使用頂點位置、頂點法線和單個UV,那么Unity最多可以批處理225個頂點。然而,如果你的著色器使用頂點位置、頂點法線、UV0、UV1和頂點切線,那么Unity只能批處理180個頂點。
??????? 2、如果GameObjects使用不同的材質實例,Unity就不能將它們批處理在一起,即使它們本質上是相同的。唯一的例外是陰影施法者的渲染。
??????? 3、帶有光貼圖的游戲對象有額外的渲染參數。這意味著,如果你想批處理光照貼圖的游戲對象,它們必須指向相同的光照貼圖位置。
??????? 4、Unity不能完全將動態批處理應用于使用多通道著色器的GameObjects。
幾乎所有的Unity著色器都支持正向渲染中的多個光源。為了實現這一點,他們為每個光處理一個額外的渲染通道。Unity只批處理第一個渲染通道。它不能批處理額外的逐像素燈光的繪制調用。
遺留延遲渲染路徑不支持動態批處理,因為它在兩個渲染通道中繪制GameObjects。第一個通道是燈光預通道,第二個通道渲染GameObjects。

其中我們要注意的是,物體必須使用相同的材質,才有可能成功進行動態合批

使用動態合批往往能減少CPU和GPU的開銷,提升游戲性能,但同時也會占用一定的內存。

三、GPU Instancing(樹木草地石塊)

使用GPU Instancing可以在一個Draw Call中同時渲染多個相同或類似的物體,從而減少CPU和GPU的開銷。

要啟用GPU Instancing,我們可以選中一個材質,然后在Inspector窗口勾選Enable GPU Instancing,這樣就可以了。

但是即使勾選了Enable GPU Instancing,也不一定會成功。

要成功使用GPU Instancing進行優化,游戲對象必須同時滿足以下條件:
1、使用相同的材質和網格。
2、材質的著色器必須支持GPU Instancing。例如標準著色器和表面著色器就支持GPU Instancing。
3、網格的頂點布局和著色器必須相同。如果網格的頂點布局或著色器不同,那么它們就無法被合并成一個實例。
4、每個實例需要有不同的變換信息(例如位置、旋轉、縮放)。雖然多個實例可以使用相同的材質和網格,但是它們必須擁有不同的變換信息才能被正確地實例化并渲染出來。
????? 另外需要注意的是,GPU Instancing與SRP Batcher不兼容。如果項目使用了SRP Batcher,并且配置為優先使用SRP Batcher而不是GPU實例化,啟用GPU實例化可能不會生效。SRP Batcher是Unity提供的一種渲染優化技術,它可以將多個網格合并成單個批次進行渲染,從而提高性能。在這種情況下,GPU實例化將被忽略。

使用GPU Instancing往往能減少CPU和GPU的開銷,提升游戲性能,但同時也會占用一定的內存。

是否要啟用GPU Instancing,要根據自己的項目來定。可以嘗試啟用,在性能分析器中看看效果如果,如果效果好,再確定啟用它。

一般來說,當場景中有大量重復的網格實例時,可以嘗試啟用GPU Instancing。例如場景中有大量樹木、草地、石塊等,這些實例具有相同的網格和材質,只是位置、顏色等屬性稍有差異,那么啟用GPU Instancing或許能夠顯著提高性能。

四、遮擋剔除

正常情況下,如果一個障礙物A擋住了后面的物體B,雖然我們看不見物體B,但是Unity仍然會消耗性能來渲染這個物體B。這樣CPU和GPU就會有一部分性能白白浪費在渲染物體B身上。

如果想在一個障礙物擋住了后面的物體后,不渲染被擋住的物體,則可以使用遮擋剔除。

以一堵墻擋住幾個小球為例,選中這堵,在Inspector窗口右上角的Static右側的下拉菜單處選擇Occluder Static,則這堵墻就是遮擋物。分別選中這些小球,在Inspector窗口右上角的Static右側的下拉菜單處選擇Occludee Static,則這些小球就是被遮擋物。

選中攝像機,要確保它啟用了Occlusion Culling屬性

創建遮擋區域的方法:
??????? 方法1、打開Occlusion Culling窗口。打開方法:Window——Rendering——Occlusion Culling——Bake。打開之后,選擇Object選項卡,點擊Occlusion Areas,點擊Create New右側的Occlusion Area。
??????? 方法2、創建一個空物體,在它身上添加Occlusion Area組件

Occlusion Area組件的Size決定了遮擋剔除區域的范圍,它越大,烘焙之后生成的遮擋剔除區域就越大。Center控制遮擋區域中心點的世界坐標。Is View Volume表示是否定義視圖體積,只有啟用了這個選項,Occlusion Area組件才可能生效。

之后,要讓遮擋剔除生效,還要在Occlusion Culling窗口的Bake選項卡中點擊右下方的Bake按鈕,進行烘焙,遮擋剔除才可能生效。而且以后每次調整完場景的遮擋物、被遮擋物、Occlusion Area組件的范圍,都要這樣烘焙一次。如果點擊旁邊的Clear按鈕,則會清除之前烘焙的數據。

Portal組件的遮擋范圍。每次調整完,或者修改過場景,都要重新烘焙。

五、光照優化

減少光源的數量

攝像機離光源近,啟動光源,攝像機離光源遠,禁用光源。

烘焙光照

光照Light組件Type設置為Point;

參與烘焙的物體比如墻,地面的static屬性設置為Contribute GI,

點擊Window===》Redering===》Lighting,點擊New Lighting Settings改名MyLightSettings;點擊Generate Lighting。烘焙比較慢,最好空閑時間烘焙,中午吃飯或者晚上烘焙。

烘焙之前Batches:26,烘焙之后Batches:16。三角面從4.3K變成3k,頂點從8.1k到6.6k。

光照優化
??????? 減少光源。
??????? 調節好每個Light組件的屬性,平衡視覺效果和游戲性能。
??????? 盡量不要用實時光照,而是考慮用烘焙光照或者混合光照,此時可以配合光照探針使用。Lighting窗口可以設置烘焙光照的參數。
??????? 減少啟用的陰影投射。
??????? 根據攝像機距離光源的距離,用腳本來決定是否啟用光源和陰影。但是這樣就會花費一些性能來計算攝像機到光源的距離。
??????? 可以考慮設置光照的陰影。無陰影的性能最好,硬陰影的性能稍差,軟陰影的視覺效果最好,但是性能是這三者中最差的。
??????? (備注:光照和陰影最影響項目的性能,其次才是模型網格和貼圖。把實時光照改成烘焙光照,可以使游戲性能大幅度增加。)
??????? 注意MeshRenderer組件上的屬性,默認情況下,Unity 會啟用陰影投射和接收、光照探針采樣、反射探針采樣和運動矢量計算。如果項目不需要這些功能中的一個或多個,請確保關閉它們。2D游戲尤其要注意,往往都不需要它們。
??????? 遠處的景物,如果確定玩家無法到達,則可以不用模型,而是把遠處的景物做成一張貼圖放到天空盒的材質中,給天空盒使用。也可以使用反射探針烘焙出一張貼圖,然后放到天空盒的材質。

六、圖片的優化

導入圖片之前的優化:

如果這張圖片是應用在移動端的,則導入Unity前,可以對這張圖的每條邊進行調整,確保每條邊的長度都是2的正整數次方個像素。例如2、4、8、16...256、512、1024、2048、4096...。這個做法只對移動端有效。

圖片導入Unity后,可以選中這張圖片,在Inspector窗口設置它的屬性。設置這些屬性,可以在發布不同的平臺,分別對該圖片進行相應的壓縮。可以在合理的范圍內減小Max Size,對于許多移動端的游戲,2048x2048 或 1024x1024 足以滿足紋理圖集的要求,而 512x512 足以滿足應用于3D模型的紋理的要求。如果圖片不需要讀寫,則可以取消勾選Read/Write Enabled,如果勾選可能導致雙倍的內存占用。Filter Mode一般選擇Bilinear即可平衡性能和視覺效果,如果選擇Point(no filter),則視覺效果不太行,但性能開銷也小,如果選擇Trilinera,則視覺效果最好,但性能開銷最大。Aniso Level一般選擇1,只有個別比較重要的圖片才需要設置為大于等于2的值。
??????? 圖片導入Unity后,會默認生成Mip Maps格式。當攝像機到這幅貼圖距離近,則顯示最原始的圖片,當攝像機距離這幅貼圖的距離遠,則這幅貼圖會變模糊,以此降低渲染的性能消耗。但由于之前顯示的一幅圖,現在變成了有多幅,所以這樣會略微增加內存消耗。如果確定本游戲的攝像機到圖片的距離幾乎不怎么變化,則可以禁用這個功能點擊該貼圖,在Inspector面板的Advanced中取消勾選Generate Mip Maps,這樣就不會生成Mip Maps,增加游戲性能。如果是2D游戲則可以禁用這個功能。如果是UI貼圖,也可以禁用這個功能
??????? 圖片導入Unity后,可以選中這張圖片,在Inspector窗口設置它在各個平臺的Format和Compressor Quality。

Format可以參考官方文檔:https://docs.unity3d.com/2021.3/Documentation/Manual/class-TextureImporterOverride.html

七、UI的優化

如果一個UGUI的控件不需要進行射線檢測,則可以取消勾選Raycast Target

盡量避免使用完全透明的圖片和UI控件。因為即使完全透明,我們看不見它,但它仍然會產生一定的性能開銷。如果UI中一定要用到很多張完全透明的圖片,則建議把這些完全透明的圖片由單獨的攝像機進行渲染,且這些UI不要疊加到場景攝像機的渲染范圍內。

盡量避免UI控件的重疊。如果多個UI有重疊的部分,則會稍微增加一些額外的計算和渲染的開銷。雖然這部分開銷通常是非常小的,但我們最好也盡量避免這種情況。
??????? UI的文字使用TextMeshPro比使用Text的性能更好。但是TextMeshPro對中文的支持不太好。盡量避免UI控件的重疊。如果多個UI有重疊的部分,則會稍微增加一些額外的計算和渲染的開銷。雖然這部分開銷通常是非常小的,但我們最好也盡量避免這種情況。
??????? UI的文字使用TextMeshPro比使用Text的性能更好。但是TextMeshPro對中文的支持不太好。

八、模型優化

模型導入Unity后,可以選中這個模型,在Inspector窗口設置它的屬性。在Model選項卡,啟用Mesh Compression可以壓縮模型,壓縮程度越高,模型精度越低,但是模型也會節省一些空間。如果該模型不需要用代碼來讀寫,則可以取消勾選Read/Write Enabled。設置Optimize Game Objects可以優化模型。如果該模型不需要使用法線,則可以把Normals設置為None。如果該模型不需要用混合變形法線,則可以把Blend Shape Normals設置為None。如果該模型不需要使用切線,則可以把Tangents設置為None。如果該模型不需要用光照UV貼圖,則可以取消勾選Swap UVs和Generate Lightmap UVs。

????????對于Rig選項卡,Animation Type如果選擇Generic Rig會比Humanoid Rig性能更好,但是一般使用Humanoid Rig是為了對人型的角色進行動畫重定向,所以要根據自己的情況來選擇。如果模型不需要使用動畫,例如一些完全不會動的石頭等物體,則可以將Animation Type選擇為None。Skin Weights默認是4,對于一些不重要的動畫對象,本變量可以設置為1,這樣可以節省計算量。建議勾選Optimize Bones,這樣會自動剔除沒有蒙皮頂點的骨骼。勾選Optimize Game Object可以提高角色動畫的性能,但是在某些情況下可能會導致角色動畫出現問題,是否勾選要看動畫效果而定。如果角色模型是可以換裝的,則在導入該模型后不要勾選這個選項,而可以在游戲運行時,該角色換裝后,通過AnimatorUtility.OptimizeTransformHierarchy來勾選這個選項。

????????對于Animation選項卡,如果模型不需要使用動畫,則可以取消勾選Import Animation。對于Animation選項卡,設置Anim.Compression可以調整動畫的壓縮方式,Off表示不壓縮動畫,這樣動畫文件可能會占用較大的空間,但是在運行時不會有任何信息損失,Keyframe Reduction表示使用關鍵幀算法來壓縮動畫,這樣會顯著減小動畫文件的大小,同時保持相對較高的動畫質量,Optimal表示會盡可能高地壓縮網格,但是這樣也會導致壓縮時間增加。

????????對于Materials選項卡,如果使用Untiy的默認材質,則可以把Material Creation Mode設置為None。
??????? Edit——Project Settings——Player——勾選Optimize Mesh Data,這樣一來,Unity會在構建的時候中對網格數據進行優化處理,以達到提高游戲性能的效果。但是這樣往往會修改網格,我們勾選之后應該要進行測試,確保沒有問題,再確定啟用它。


??????? 用LOD技術,使用Unity自帶的LOD Group組件,并根據項目的情況來調整該組件的屬性。Untiy資源商店也有一些其它的LOD插件。
??????? 把多個模型的網格合并為一個網格。可以使用自己寫代碼,使用Unity自帶的CombineMeshes方法,也可以使用資源商店的插件,在資源商店搜Mesh Combine可以搜索到相關的插件,例如Easy Mesh Combine Tool等插件。
??????? 減少模型的頂點、面、材質、骨骼、蒙皮網格。這一般由美術人員來完成。

九、LOD Group

????????LOD的原理,就是我們可以為一個游戲對象設定多個模型,這些模型消耗的游戲性能由高到低排列。會根據攝像機距離模型的遠近自動顯示對應的模型。
???????? 近的時候顯示最精細的模型,距離中等的時候顯示沒那么精細的模型,遠的時候顯示粗糙的模型,最遠的時候可以隱藏該模型。

????????使用LOD技術能起到優化渲染性能的效果。但是使用LOD技術也會增加內存占用。

????????在Unity中可以使用LODGroup組件來實現LOD技術

????????LOD級別LOD 0、LOD 1、LOD 2分別表示攝像機從近處看、從中等距離處看、從遠處看時,所使用的模型的信息。Culled表示不渲染該模型。

????????點開下方的LOD 0、LOD 1、LOD 2,點擊+號可以添加在這種情況下要顯示的模型。

把LODGroup組件添加在一個空物體身上。這個空物體身上不添加MeshRenderer組件,也不添加MeshFilter組件,但可以添加碰撞器。如果要添加剛體、腳本等,也可以添加到這個空物體身上的。
???????? 這個空物體要渲染的每一個模型都要作為它的子物體,它們的身上要添加MeshRenderer組件和MeshFilter組件,用于渲染這個模型,但是不要給它們添加碰撞器。
???????? 在該空物體的LODGroup組件中,點擊選中要設置的LOD級別,在Renderers下方點擊Add可以選擇要顯示的游戲對象,點擊-號可以移除該游戲對象。

????????Edit——Project Settings——Quality中有控制整個項目LOD的參數。
???????? LOD Bias的值小,則攝像機離物體的距離稍微有些變化,則不同的LOD級別就會切換。如果LOD Bias的值大,則攝像機需要與物體有比較大的距離變化,不同的LOD級別才會切換。

十、合并網格

合并網格就是把多個網格合并為一個整體,從而提升游戲性能。

但是這樣一來,我們就不能單獨控制這些網格運動了,只能控制合并后的整個網格運動。而且合并的網格使用的材質必須是相同的,合并才可能成功,否則合并之后依然不能提升性能。

可以在Unity資源商店搜Mesh Combine,下載相應的插件來實現合并網格的功能,例如Easy Mesh Combine Tool等插件。

??????? Easy Mesh Comline Tool插件,Package Manager。從資源商店導入插件。

Window===》Easy Mesh Combine Tool 打開之后點擊Make Group and

Combile。

十一、動畫優化

????????設置Animator組件的Culling Mode。Always Animate表示如果該動畫不可見,也會播放它。Cull Update Transformations表示如果該動畫不可見,則不會渲染該動畫,但是依然會根據該動畫的播放來改變游戲對象的位置、旋轉、縮放,這樣是常用的選項。Cull Completely表示完全不會播放該動畫,不但不會渲染該動畫,而且也不會改變游戲對象的位置、旋轉、縮放。
????????

????????禁用SkinMesh Renderer組件的Update When Offscreen可以讓角色在不可見的時候動畫不更新,這樣可以減少計算量,提升性能。


??????? 對于Animator組件,可以使用Animator.StringToHash方法獲得指定字符串的哈希值,再把它作為參數傳入Animator型對象.GetXXX方法和Animator型對象.SetXXX方法中進行使用。

??????? int hash = Animator.StringToHash("Jumping");

??????? animator.SetBool(hash,true);


??????? 不用的Animation組件和Animator組件可以考慮刪掉,因為只要它們存在,就會消耗性能來檢測當前的狀態和過渡條件。
????????

一些簡單的動畫可以使用DoTween、iTween等插件實現,而不需要每個動畫都用Animator來實現。

十二、音頻優化

????????Unity支持后綴為.wav、.ogg、.mp3的音頻文件,但建議使用.wav,因為Unity對它的支持特別好。注意:Unity在構建項目時總是會自動重新壓縮音頻文件,因此無需刻意提前壓縮一個音頻文件再導入Unity,因為這樣只會降低該音頻文件最終的質量。


??????? 把音頻文件導入Unity后,選中它,可以在Inspector窗口設置它的屬性。勾選Force To Mono,這樣就會把這個音頻文件設置為單聲道。可以節省該資源所占據的空間。因為很少有移動設備實際配備立體聲揚聲器。在移動平臺項目中,將導入的音頻剪輯強制設置為單聲道會使其內存消耗減半。此設置也適用于沒有立體聲效果的任何音頻,例如大多數UI聲音效果。

????????對于Load Type選項,小文件(小于200kb)選擇Decompress on Load,中等大小的文件(大于等于200kb)選擇Compressed In Memory,比較大的文件(如背景音樂)選擇Streaming。????????????????

????????對于Compression Format的選項,PCM表示不壓縮,Vorbis表示壓縮,但也會盡量保證音頻的質量,ADPCM表示壓縮,且壓縮的程度比Vobis更高。由于PCM不會壓縮音頻,所以占用的空間大,應盡量少用,長時間的音頻文件可以使用Vorbis,短時間的音頻文件可以使用ADPCM。

Sample Rate Setting用于控制音頻文件的采樣率,對于移動平臺,采樣率不需要太高,建議選擇Override Sample Rate,然后在下方的Sample Rate選擇22050Hz,一般這樣就夠用了。

十三、物理優化

????????使用簡單的碰撞器進行碰撞檢測,如球體碰撞器、盒子碰撞器、膠囊體碰撞器,少用網格碰撞器等復雜的碰撞器。即使用多個簡單的碰撞器組合在一起,也往往比使用網格碰撞器的性能要好。
??????? 如果要把多個碰撞器組合成一個碰撞器,可以用復合碰撞器。
????????

????????如果同一個功能既可以用碰撞器來做,也可以用觸發器來做,則往往使用觸發器來做,性能更好。
??????? 盡量減少剛體組件,因為剛體組件的物理計算較多。


??????? 如果勾選剛體組件的Is Kinematic,則性能會有所提高。但這樣一來,這個剛體只會給別的剛體施加力,自己不會受到別的剛體施加的力的作用。


??????? Edit——Project Settings——Player——勾選Optimization下方的Prebake Collision Meshes,可以提高碰撞的效率,但是構建游戲的時間會增長


??????? Edit——Project Settings——Physics或者Physics 2D——設置Layer Collision Matrix。它規定了哪些Layer層的游戲對象可以彼此碰撞,哪些Layer層的游戲對象會忽略碰撞。如果有些Layer層的游戲對象之前不需要進行碰撞,則可以在這里設置,取消勾選則表示不會碰撞。


??????? Edit——Project Settings——Time——稍微調大Fixed Timestep,這樣可以稍微提升游戲性能,但是物體的運動可能會出現問題。

十四、代碼優化

代碼優化:
??????? 使用AssetBundle作為資源加載方案。而且經常一起使用的資源可以打在同一個AssetBundle包中。盡量避免同一個資源被打包進多個AB包中。壓縮方式盡量使用LZ4,少用或不要用LZMA的壓縮方式。

????????如果確定后續開發不會升級Unity版本,則可以嘗試啟用打包選項BuildAssetBundleOption.DisableWriteType,這樣TypeTree信息不會被打到AB包中,可以極大減小包體大小以及運行加載時的內存開銷。
??????? 使用AssetBundle或者Addressables加載的資源,如果不使用,要記得卸載它們,否則會造成內存泄漏。
??????? 不用的資源要釋放掉,不用的引用類型的變量也要賦值為null不要讓它們一直占著內存中。
??????? 加載資源時盡量使用異步加載。

?????? ?
??????? 頻繁創建和銷毀對象,可以使用對象池。
?????? ?
??????? 切換場景時,舊的場景要釋放掉,不用的資源也可以考慮釋放掉,也可以考慮用System.GC.Collect來進行一次垃圾回收


??????? 鎖定游戲的幀率 。幀率為30,游戲會明顯卡頓,但是對于手游來說,消耗手機的電量比較少。幀率為45,游戲有一點點卡,但還湊合,消耗電量中等。幀率為60,游戲很流暢,但消耗手機的電量會比較多。可以用Application.targetFrameRate來鎖定幀率,也可以用UnityEngine.Rendering命名空間中的OnDemandRendering.renderFrameInterval來鎖定幀率。
??????? 盡量少用foreach語句,可以改為for語句。因為每次使用foreach語句會造成微量的內存垃圾。
????????

????????要判斷GameObject型對象.tag是不是某個標簽,使用GameObject型對象.CompareTag方法會更高效
????????

????????盡量少用GameObject.Find方法和Object.FindObjectOfType方法來查找游戲對象,可以提前把要查找的游戲對象存儲在變量、列表、字典等容器中,方便查找。也可以用GameObject.FindGameObjectWithTag方法來查找游戲對象。
????????

在UI顯示字符串的時候,如果一些內容是固定的,我們可以把它拆分開來,這樣可以減少使用+號來拼接的次數,減少內存垃圾的產生。例如“殺敵數:999”,其中“殺敵數:”是固定的,冒號后面的數字才是會變的,那么我們可以用兩個Text組件分別記錄它們,改變的時候只改變冒號后面的數字。
????????

????????頻繁對字符串賦新的值,或者頻繁拼接字符串的時候,可以使用StringBuilder代替string
??????? 如果要頻繁操作某腳本,不要每次都用GetComponent方法來獲取這些腳本。可以用一個變量存儲起獲得的這個腳本,之后要訪問它,就直接訪問這個變量即可。也可以考慮在生命周期方法Awake或者Start中聲明變量來存儲,之后訪問這個變量即可。
????????

????????盡量少用正則表達式。雖然正則表達式的形式看上去比較簡便,但是使用它會造成一定的性能消耗,且會產生內存垃圾。
??????? 盡量少用LINQ語法,因為每次使用LINQ都會產生一定量的內存垃圾。
??????? 盡量少用Camera.main來訪問主攝像機,因為每次訪問它,實際上Unity都是從場景中查找它的。可以聲明一個變量存儲它,在生命周期方法Awake或Start中獲取主攝像機的應用。
??????? ???????

????????在Animator、Shader中使用Get方法和Set方法時,不傳入字符串作為參數,而是傳入哈希值。例如Animator組件可以使用Animator.StringToHash方法獲得指定字符串的哈希值,再把它作為參數傳入Animator組件的Get方法或Set方法中進行使用。例如Shader,則可以用Shader.PropertyToID方法來獲取指定屬性的ID
????????

????????使用非分配物理API。例如使用Physics.RaycastNonAlloc方法代替Physics.RaycastAll方法,使用Physics.SphereCastNonAlloc方法代替Physics.SphereCastAll方法,以此類推。Physics2D類也有類似的方法。

??????? 一般情況下,整數的數學運算比浮點數的數學運算效率高,浮點數的數學運算比矢量的數學運算效率高。可以靈活運用數學的加法交換律、加法結合律、乘法交換律、乘法結合律,在保證結果不變的前提下,調整運算順序,減少浮點數的數學運算和矢量的數學運算
????????

????????使用高效的算法進行計算
??????? 每次執行Debug.Log來打印信息會消耗極少量的性能,如果要在游戲正式發布之后不執行某些Debug.Log的語句,但又不想把這些代碼刪掉,則可以使用宏來禁止在游戲正式發布之后執行Deubg.Log的語句。例如使用#if語句或者Conditional特性。


??????? 盡量減少在生命周期方法Update、FixedUpdate、LateUpdate中的邏輯。其中有些不需要頻繁執行的邏輯,可以使用協程或者Invoke方法,每隔指定的秒數執行一次或每隔指定的幀數執行一次。
????????

????????盡量避免頻繁的裝箱拆箱操作。也可以使用泛型,這樣就能避免裝箱拆箱。但是要注意,Lua熱更新對泛型的支持不太好。


??????? 如果物體身上添加了剛體組件,則盡量用剛體組件的方法來移動它,而不是用Transform類的方法來移動它。
??????? 如果物體身上添加了CharacterController組件,則盡量用CharacterController組件的方法來移動它,而不是用Transform類的方法來移動它。同理,如果物體身上添加了剛體組件,則應盡量用剛體組件的方法來移動它,而不是用Transform類的方法來移動它。


??????? 應盡量避免DontDestroyOnLoad中加載的資源過多,因為它在切換場景的時候不會被釋放,聲明的變量以及加載的資源會一直占用著內存。我們可以考慮把一些資源不用的資源釋放掉,需要的時候再加載它。


??????? 不使用組件可以刪掉,這樣可以節省一些內存。常見的有AudioSource組件、Animator組件、Animation組件等,如果它們不需要使用,則可以刪掉。


??????? 寫一個類繼承AssetPostProcessor,然后定義里面特定的方法,以此來自動設置資源導入Unity之后的屬性。


??????? 盡量避免閉包。因為閉包會產生額外的內存開銷。

Shader優化:
??????? 修改Shader的代碼,或者自定義一個Shader
??????? 修改渲染管線的源碼,改成符合自己項目的渲染管線,或者自定義渲染管線。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/82660.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/82660.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/82660.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python+AI Agent:解鎖MCP Servers的智能潛力

💝💝💝歡迎蒞臨我的博客,很高興能夠在這里和您見面!希望您在這里可以感受到一份輕松愉快的氛圍,不僅可以獲得有趣的內容和知識,也可以暢所欲言、分享您的想法和見解。 推薦:「storms…

uni-app學習筆記十五-vue3頁面生命周期(一)

頁面生命周期概覽 vue3頁面生命周期如下圖所示: onLoad 此時頁面還未顯示,沒有開始進入的轉場動畫,頁面dom還不存在。 所以這里不能直接操作dom(可以修改data,因為vue框架會等待dom準備后再更新界面)&am…

【排序算法】快速排序詳解--附詳細流程代碼

快速排序算法 介紹 快速排序(Quick Sort)是一種高效的分治排序算法,由英國計算機科學家 Tony Hoare 于 1960 年提出。它是實際應用中最常用的排序算法之一。快速排序的基本思想是:選擇一個"基準"(pivot&am…

【監控】Prometheus中的告警機制介紹

prometheus實戰之三:告警規則_驗證prometheus告警規則-CSDN博客 Prometheus是一款開源的系統監控和告警工具,其告警功能是保障系統穩定運行的重要部分。以下將從告警的整體架構、核心概念、規則配置以及具體的通知流程等方面對Prometheus中的告警進行介…

53、用例(Use Case)詳解

1. 定義與核心概念 用例(Use Case) 是軟件工程中用于描述系統功能需求的核心工具,它通過結構化的方式定義系統與外部參與者(用戶、其他系統)之間的交互行為,以實現具體的業務目標。用例強調從用戶視角出發…

對比Redis與向量數據庫(如Milvus)在AI中的應用

對比Redis與向量數據庫(如Milvus)在AI中的應用 在AI架構中,緩存系統的設計直接影響響應速度、資源成本以及推理路徑是否高效。而面對不同的AI業務訴求,選用什么類型的緩存系統、如何搭配,往往是系統架構設計中必須深入…

Oracle 的 MOVE 操作是否重建表?

Oracle 的 MOVE 操作是否重建表? Oracle 的 ALTER TABLE ... MOVE 操作實質上是重建表的物理存儲結構,但保留表的邏輯定義不變。 MOVE 操作的本質 物理重建: 創建新的數據段(物理存儲結構)將原表數據按順序重新插入到…

數據庫中表的設計規范

表的結構 列:由多個字段構成,每個字段存儲單一數據項,列的先后順序對表沒有影響 行:記錄,一個表中不能存在完全相同的兩行,行的順序對表沒有影響 主鍵:primary key 表中的一列或多列組合起來…

[學習]C語言指針函數與函數指針詳解(代碼示例)

C語言指針函數與函數指針詳解 文章目錄 C語言指針函數與函數指針詳解一、引言二、指針函數(函數返回指針)定義與語法典型應用場景注意事項 三、函數指針(指向函數的指針)定義與聲明初始化與調用賦值方式調用語法 高級應用回調函數…

Python 實現桶排序詳解

1. 核心原理 桶排序是一種非比較型排序算法,通過將數據分配到多個“桶”中,每個桶單獨排序后再合并。其核心步驟包括: 分桶:根據元素的范圍或分布,將數據分配到有限數量的桶中。桶內排序:對每個非空桶內的…

brep2seq 論文筆記

Brep2Seq: a dataset and hierarchical deep learning network for reconstruction and generation of computer-aided design models | Journal of Computational Design and Engineering | Oxford Academic 這段文本描述了一個多頭自注意力機制(MultiHead Attenti…

在 LangGraph 中集成 Mem0 記憶系統教程

簡介 LangGraph 是一個強大的對話流程編排框架,而 Mem0 則是一個高效的記憶系統。本教程將介紹如何將兩者結合,創建一個具有記憶能力的客服助手系統。 環境準備 首先安裝必要的依賴: pip install langgraph mem0 langchain openai基礎配置…

ceph 報錯 full ratio(s) out of order

full ratio(s) out of order你遇到的錯誤信息: full ratio(s) out of order說明你設置的 OSD 空間使用閾值之間的數值順序不正確,即: nearfull_ratio ≤ backfillfull_ratio ≤ full_ratio ≤ osd_failsafe_full_ratio如果它們的關系不滿足這個順序,Ceph 就會報這個錯誤。…

NB-IoT NPUSCH(三)-資源映射

資源映射單獨做一章節,是因為NPUSCH的資源映射比較復雜。與LTE不同,為了提高數據傳輸的質量,NB-IoT的數據會有重復傳輸。NPUSCH一開始生成的TBS只與子載波個數、RU個數有關,與重復次數沒有關系。初始產生的數據為 個時隙&#xff…

華為OD機試真題——荒島求生(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳實現

2025 B卷 200分 題型 本專欄內全部題目均提供Java、python、JavaScript、C、C++、GO六種語言的最佳實現方式; 并且每種語言均涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、3個測試用例以及綜合分析; 本文收錄于專欄:《2025華為OD真題目錄+全流程解析+備考攻略+經驗分…

centos7安裝MySQL(保姆級教學)

在 Linux 系統的軟件管理中,YUM(Yellowdog Updater, Modified)包管理器是不可或缺的工具,而 YUM 源的選擇與配置直接影響著軟件安裝與更新的效率。本文將深入解析網絡 YUM 源的分類,詳細介紹如何使用知名平臺提供的 YU…

DeepSeek 賦能教育游戲化:AI 重構學習體驗的技術密碼

目錄 一、引言:教育游戲化與 DeepSeek 的相遇二、DeepSeek 技術剖析2.1 核心架構2.2 關鍵技術 三、教育游戲化設計的奧秘3.1 概念與意義3.2 常見方法與元素3.3 成功案例借鑒 四、DeepSeek 在教育游戲化設計中的多面應用4.1 個性化學習路徑打造4.2 智能教學輔助工具4…

WPF命令與MVVM模式:打造優雅的應用程序架構

?? 打造優雅的應用程序架構 1. ?? 命令系統基礎1.1 ?? 為什么需要命令?1.2 ??? ICommand接口1.3 ??? 實現基本命令2. ??? MVVM模式詳解2.1 ?? MVVM三大組件2.2 ??? 創建ViewModel基類2.3 ?? 典型ViewModel示例3. ?? 命令綁定實戰3.1 ?? View中的命令…

真實案例拆解:智能AI客服系統中的兩類緩存協同

真實案例拆解:智能客服系統中的兩類緩存協同 在AI客服系統中,“響應速度”與“語義準確性”是一對天然的矛盾體。為了實現秒級應答與智能理解的雙重目標,系統需要在技術架構中融合精確命中的緩存系統(如Redis)與模糊語義識別的向量數據庫(如Milvus)。這兩種能力的結合,…

FastAPI與MongoDB分片集群:異步數據路由與聚合優化

title: FastAPI與MongoDB分片集群:異步數據路由與聚合優化 date: 2025/05/26 16:04:31 updated: 2025/05/26 16:04:31 author: cmdragon excerpt: FastAPI與MongoDB分片集群集成實戰探討了分片集群的核心概念、Motor驅動配置技巧、分片數據路由策略、聚合管道高級應用、分片…