Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
遮蔽剔除
在 3D 算繪引擎中,遮蔽剔除 是執行隱藏幾何體移除的過程。
在本指南中,我們將學到:
什麼是遮擋剔除的優點缺點。
如何在 Godot 中設定遮擋剔除。
排除遮擋剔除常見問題。
也參考
你可以透過 Occlusion Culling and Mesh LOD 範例專案 來實際觀察遮擋剔除的運作方式。
為什麼要使用遮擋剔除
在這個有數百個房間相鄰堆疊的範例場景中,一個動態物件(紅色球體)隱藏在明亮房間的牆後面(在門的左側):
具有遮擋剔除友好佈局的範例場景
停用遮擋剔除後,必須算繪照亮房間後方的所有房間。動態物件也必須被算繪:
遮擋剔除**停用**的範例場景(線框)
啟用遮擋剔除後,只需算繪實際可見的房間。動態物件也被牆壁遮擋,因此不再需要算繪:
啟用 的遮蔽剔除範例場景(線框)
由於引擎要做的工作較少(需要算繪的頂點較少,繪製呼叫也較少),因此只要場景中有足夠的遮擋剔除機會,效能就會提高。這意味著遮擋剔除在室內場景中最有效,最好有許多較小的房間,而不是較少的較大房間。將此與 網格的細節級別(LOD) 和 可見範圍(HLOD) 結合起來,可以進一步提高效能效益。
備註
當使用 Forward+ 算圖器時,引擎已經會執行 深度預處理。這個步驟會在場景實際材質算繪前,先只繪製深度資訊,用來確保每個不透明像素只會被著色一次,大幅降低過度繪製的成本。
使用 Mobile 算圖器時效果最明顯,因為該算圖器為了效能並沒有深度預處理,所以遮擋剔除可以顯著減少著色時的過度繪製。
儘管如此,即使使用深度預通道,複雜 3D 場景中的遮蔽剔除仍然具有明顯的優勢。然而,在遮蔽剔除機會很少的場景中,遮蔽剔除可能不值得增加設定和 CPU 使用率。
Godot 的遮擋剔除運作方式
備註
「遮擋器」指的是用來遮蔽視線的形狀,而「被遮蔽物」則是被隱藏的物件。
在 Godot 中,遮蔽剔除的工作原理是將場景的遮蔽幾何圖形光柵化到 CPU 上的低解析度緩衝區。這是使用軟體光線追蹤庫 Embree 完成的。
然後,引擎使用此低解析度緩衝區來測試遮擋物的 AABB 與遮擋物形狀。被遮擋物的 AABB 必須被要剔除的遮擋物形狀 完全遮擋 。
因此,較小的物件比較大的物件更有可能被有效剔除。較大的遮蔽物(例如牆壁)也往往比較小的遮擋物(例如裝飾道具)更有效。
設定遮擋剔除
使用遮蔽剔除的第一步是啟用 算繪 > **遮蔽剔除 > 使用遮蔽剔除 專案設定。 (確保在“專案設定”對話框中啟用“高級”開關才能看到它。)
專案設定會立即應用,無需重啟編輯器。
啟用專案設定後,您仍然需要建立一些遮蔽物。出於性能原因,引擎不會自動使用所有可見幾何體作為遮擋剔除的基礎。相反,引擎需要簡化的場景表示,僅需要烘焙靜態物件。
有兩種方法可以為伺服器匯出專案:
自動烘焙遮擋物(建議)
備註
目前 遮擋器 烘焙過程中僅考慮 MeshInstance3D 節點。烘焙遮蔽物時,不 考慮 MultiMeshInstance3D、GPUParticles3D、CPUParticles3D 和 CSG 節點。如果您希望將它們視為遮擋物,則必須手動建立(大致)以配對其幾何形狀的遮擋物形狀。
自 Godot 4.4 起,只要在烘焙遮擋物之前,先將 CSG 節點 轉換為 MeshInstance3D,就能納入烘焙流程。
此限制不適用於*被遮蔽者*。任何繼承自 GeometryInstance3D 的節點型別都可以被遮蔽。
啟用上述遮擋剔除專案設定後,將 OcclusionrInstance3D 節點新增至包含 3D 關卡的場景。
選擇 OccluderInstance3D 節點,然後點擊 3D 編輯器視窗頂部的 Bake Occlusionrs。烘焙後,OccluderInstance3D 節點將包含一個 Occluder3D 資源,用於儲存關卡幾何的簡化版本。此遮擋物幾何體在 3D 視圖中顯示為紫色線框線(只要在 透視 選單中啟用 查看 Gizmos)。然後使用此幾何體為靜態和動態被遮蔽物提供遮蔽剔除。
烘焙後,您可能會注意到動態物件(例如玩家、敵人等)包含在烘焙的網格中。為了防止這種情況發生,請在 OccluderInstance3D 上設定 Bake > Cull Mask 屬性,以排除某些視覺層的烘焙。
例如,您可以停用剔除蒙版上的第 2 層,然後將動態物件的 MeshInstance3D 節點配置為位於視覺層 2(而非第 1 層)上。為此,請選擇相關的MeshInstance3D 節點,然後在**VisualInstance3D > Layers** 屬性上,取消選取圖層1,然後選取圖層2。配置剔除遮罩和圖層後,依照上述流程再次烘焙遮擋物。
手動放置遮擋器
這種方法更適合專門的用例,例如為 MultiMeshInstance3D 設定或 CSG 節點建立遮蔽(由於上述限制)。
啟用上述遮擋剔除專案設定後,將 OcclusionrInstance3D 節點新增至包含 3D 關卡的場景。選擇 OccluderInstance3D 節點,然後選擇要新增至 Occlusionr 屬性中的遮擋器型別:
QuadOcclusionr3D(單平面)
BoxOcclusionr3D(長方體)
SphereOcclusionr3D(球狀遮擋器)
PolygonOccluder3D(具有任意數量點的 2D 多邊形)
還有 ArrayOccluder3D,其點無法在編輯器中修改,但可用於從腳本進行程式產生。
預覽遮擋剔除效果
您可以啟用除錯繪製模式來預覽遮擋剔除實際「看到」的內容。在3D 編輯器視窗的左上角,按一下**透視** 按鈕(或**正交**,取決於您目前的相機模式),然後選擇**顯示進階... > 遮擋剔除緩衝區**。這將顯示引擎用於遮蔽剔除的低解析度緩衝區。
在同一選單中,您還可以啟用**查看資訊**和**查看影格時間**來查看右下角的繪製呼叫和算繪像素(頂點+索引)的數量,以及右上角算繪的每秒影格數。
如果在顯示此資訊時在專案設定中切換遮擋剔除,您可以看到遮擋剔除對場景效能的改善程度。請注意,性能優勢在很大程度上取決於 3D 編輯器相機的視角,因為遮擋剔除僅在相機前面存在遮擋物時才有效。
若要在執行時動態切換遮擋剔除,可以在 root viewport 上設定 use_occlusion_culling 屬性,如下:
get_tree().root.use_occlusion_culling = true
GetTree().Root.UseOcclusionCulling = true;
在執行時切換遮擋剔除,有助於比較專案的效能差異。
效能考量
在建構關卡時考慮遮擋
這就是很多專業人士的秘密。好的關卡設計並不只是滿足遊戲性的需求,也應該同時考慮遮擋。
對於室內環境,新增不透明的牆壁以定期“打破”視線,並確保一次不會看到太多場景。
對於大型開放場景,請盡可能使用類似金字塔的結構來確定地形的標高。與任何其他地形形狀相比,這提供了最大的剔除機會。
遊戲過程中避免移動 OccluderInstance3D 節點
這包括移動 OccluderInstance3D 節點的父節點,因為這將導致節點本身在全域空間中移動,因此需要重建 BVH 。
切換 OccluderInstance3D 的可見性(或其父級之一的可見性)並不那麼昂貴,因為更新只需要發生一次(而不是連續發生)。
例如,如果您有一扇滑動門或旋轉門,則可以使 OccluderInstance3D 節點不是門本身的子節點(以便遮擋器永遠不會移動),但您可以在門開始打開後隱藏 OccluderInstance3D 可見性。一旦門完全關閉,您就可以重新顯示 OcclusionrInstance3D。
如果您絕對必須在遊戲過程中移動 OcclusionrInstance3D 節點,請為其使用原始 Occlusionr3D 形狀,而不是複雜的烘焙形狀。
使用盡可能簡單的遮擋物形狀
如果您發現複雜 3D 場景中效能低或卡頓,則可能表示 CPU因算繪詳細遮蔽物而過載。選擇 OccluderInstance3D 節點,增加 Bake > Simplification 屬性,然後再次烘焙遮蔽物。
請記得保持簡化值合理。對於關卡幾何形狀來說太高的值可能會導致發生不正確的遮蔽剔除,如 被遮蔽物在不該被剔除時卻被剔除了 所示。
如果這仍然沒有導致足夠低的 CPU 使用率,您可以嘗試調整 算繪 > 遮擋剔除 > BVH 建構品質 專案設定和/或減少 算繪 > 遮擋剔除 > 每線程遮擋光線。您需要在「專案設定」對話方塊中啟用「進階」開關才能查看這些設定。
疑難排解
我的被遮蔽者在該被剔除的時候卻沒有被剔除
在遮擋器一側:
首先,仔細檢查 OccluderInstance3D 中的 Bake > Cull Mask 屬性是否設定為允許烘焙您想要的網格。 MeshInstance3D 節點的可見性層必須存在於剔除遮罩中,網格才能包含在烘焙中。
另請注意,遮擋器烘焙僅考慮具有“不透明”材質的網格。表面將*透明*材質將**不**包含在烘焙中,即使應用在其上的紋理是完全不透明的。
最後,請記住,烘焙遮擋物時**不**考慮 MultiMeshInstance3D、GPUParticles3D、CPUParticles3D 和 CSG 節點。作為解決方法,您可以手動為這些節點新增 OccluderInstance3D 節點。
在被遮蔽方:
確保**額外剔除餘裕**設定為盡可能低(通常應為``0.0``),並且在物件的 GeometryInstance3D 部分中停用**忽略遮蔽剔除**。
另外,檢查 AABB 的大小(選擇節點時以橘色框表示)。此軸對齊的邊界框必須被遮擋物形狀*完全*遮擋,才能隱藏被遮擋物。
被遮蔽物在不該被剔除時卻被剔除了
造成這種情況的最可能的原因是,遮擋物烘焙中包含的物件在烘焙遮擋物後已被移動。例如,當行動關卡幾何圖形或重新排列其佈局時,可能會發生這種情況。要解決此問題,請選擇 OccluderInstance3D 節點並再次烘焙遮擋物。
這種情況也可能發生,因為動態物件包含在烘焙中,儘管它們不應該包含在內。使用遮蔽剔除除錯繪製模式 occlusion culling debug draw mode 尋找不應出現的遮蔽形狀,然後相應調整烘焙剔除蒙版 adjust the bake cull mask accordingly 。
最後一個可能的原因是在遮擋器烘焙過程中過於激進的網格簡化。選擇 OccluderInstance3D 節點,減少 Bake > Simplification 屬性,然後再次烘焙遮蔽物。
作為最後的手段,您可以啟用被遮蔽者的 忽略遮蔽剔除 屬性。這將抵消該物件的遮蔽剔除的效能改進,但對於永遠不會被剔除的物件(例如第一人稱視圖模型)執行此操作是有意義的。