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.

3D 效能最佳化

剔除

Godot 會自動執行視錐剔除,以避免繪製在視窗外的物件。這對於小型場景的遊戲效果很好,但在大型關卡中可能很快就會遇到效能瓶頸。

遮蔽剔除

舉例來說,當你在小鎮中走動時,實際上你只能看到你所在街道上的幾棟建築物,還有天空與頭頂飛過的幾隻鳥。但對於單純的算繪器來說,它認為你能看到整個小鎮。它不只會算繪你面前的建築,還會算繪後面的街道、街上的行人,以及再更後方的建築。你很快就會遇到需要算繪比實際可見多 10 倍、甚至 100 倍物件的情況。

情況並沒有看起來那麼糟,因為 Z 緩衝區通常會讓 GPU 只對前面的物件進行完整著色。這稱為 深度預先通過 (depth prepass),在 Godot 使用 Forward+ 或相容性算繪模式時預設啟用。但不必要的物件仍然會降低效能。

One way we can potentially reduce the amount to be rendered is to take advantage of occlusion. Godot offers an approach to occlusion culling using occluder nodes. See 遮蔽剔除 for instructions on setting up occlusion culling in your scene.

備註

在某些情況下,你可能需要調整你的關卡設計以增加更多遮擋機會。例如,你可以增加更多牆壁,避免玩家看到過遠的區域,否則因為遮擋剔除機會減少而導致效能下降。

透明物件

Godot 會依據 MaterialShader 對物件排序以提升效能。然而,透明物件無法這麼做。透明物件需要從遠到近繪製,以正確混合背景。因此,請儘量減少透明物件的使用。如果某個物件只有一小部分需要透明,建議將該部分拆分成獨立的表面,給它專屬材質。

更多資訊請參考 GPU 最佳化 文件。

細節層級(LOD)

在某些情境下,尤其是遠距離時, 以更簡化的模型取代複雜幾何體 是個好方法。最終使用者很可能分辨不出差異。想像一下遠方有大量樹木的情境,你可以採用多種策略依照距離替換模型,例如使用較低面數(Low Poly)的模型,或利用透明度模擬更複雜的幾何外觀。

Godot 4 提供了多種控制細節層級(LOD)的方法:

雖然這些方法可以單獨使用,但搭配在一起時效果最佳。例如,你可以設定可見範圍來隱藏玩家無法注意到的遠距粒子特效,同時利用網格 LOD 讓粒子在遠處時以較低細節算繪。

可見範圍也很適合為遠距幾何體設置「冒充物」(impostor)(見下文)。

看板物件與冒充物(Billboard 與 Impostor)

利用透明度實現 LOD 最簡單的方式就是使用看板(Billboard)。例如,你可以用一個透明四邊形來代表遠方的樹。這能大幅降低算繪成本,但如果有大量樹彼此重疊時,透明度會消耗填充率(Fill Rate)。(更多關於填充率的資訊請見 GPU 最佳化 )。

另一種方式不是只用單一樹木,而是把多棵樹作為一個群組一次算繪。如果該區域玩家只能遠觀,無法靠近,這種方法特別有效。

你可以預先算繪物件在不同角度下的影像,製作成冒充物(Impostor)。甚至可以進一步,定期把物件當前視角重新算繪到貼圖上作為冒充物。在遠處時,視角要有明顯變化需要很大移動距離。雖然實作上較為複雜,但對某些專案來說非常值得。

使用自動實例化

此功能僅在 Forward+ 算繪器中實作,Mobile 與 Compatibility 不支援。

若場景中有大量相同物件,可利用自動實例化以減少 draw call 次數。對於使用相同網格與材質的 MeshInstance3D,這會自動生效,無需手動設定。

自動實例化要能發揮作用,材質必須為不透明或通過 Alpha 測試(alpha scissor 或 alpha hash)。採用 Alpha 混合或深度預通過的材質不會以此方式實例化,需改用下文所述的 MultiMesh。

使用手動實例化(MultiMesh)

如果需要在同一區域或附近繪製多個相同物件,請考慮使用 MultiMesh。MultiMesh 可以用極低效能成本繪製成千上萬個物件,非常適合用於大量群體、草地、粒子等場景。

詳情請參閱 使用 MultiMesh 文件。

烘焙光照

燈光運算是最吃資源的算繪操作之一,特別是即時光照、陰影(尤其是多盞燈),以及 全域照明。這些在低階裝置上可能完全跑不動。

建議使用烘焙光照,尤其是在行動裝置上。這種方法畫面效果很棒,但缺點是光源無法動態改變。有時這是值得的取捨。

關於如何使用烘焙光照貼圖,請參考 使用光照貼圖全域光照。為了最佳效能,請將燈光的烘焙模式設為 靜態**(Static),而非預設的 **動態,如此可略過已烘焙網格的即時光照運算。

靜態**燈光的缺點是無法把陰影投射到已烘焙光照的網格上。這會讓戶外場景與動態物件看起來比較單調。效能與畫質之間的折衷方案,是讓 :ref:`class_DirectionalLight3D` 使用 **動態,而大多數(甚至全部)點光源與聚光燈則用 靜態

動畫與蒙皮(Skinning)

在某些平台上,動畫與頂點動畫(如蒙皮與變形)效能消耗非常大。你可能需要大幅降低動畫模型的面數,或限制同時出現在畫面的數量。你也可以針對遠距或被遮擋的模型減少動畫播放速率,甚至在玩家不會注意時直接暫停動畫。

你可以利用 VisibleOnScreenEnabler3DVisibleOnScreenNotifier3D 節點來達成上述控制。

大型世界

如果你要設計大型世界,會遇到跟小型遊戲完全不同的挑戰與考量。

大型世界通常需要分割為可隨需求載入的區塊(Tiles),你在世界中移動時再動態加載。這可以避免記憶體暴增,並將運算集中在玩家所在區域。

在大型世界中,由於浮點數誤差,可能會出現算繪或物理異常。你可以參考 大世界座標 來解決這個問題。如果無法使用大型世界座標系統,也可以考慮讓世界隨玩家移動、或定期平移原點來保持所有物件圍繞 Vector3(0, 0, 0) 為中心。