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 專案;2D 專案較少需要。此外,與 3D 繪圖不同,啟用大世界座標時,2D 繪圖目前無法從提升精度中獲益。

為什麼要使用大世界座標?

在 Godot 中,物理模擬和繪圖都依賴於 浮點數。然而,電腦中的浮點數有 有限的精度與範圍。這對於有著龐大世界的遊戲(如太空或行星規模的模擬遊戲)而言,會是個問題。

當值接近 0.0 時,浮點數的精度最高。隨著值離 0.0 越遠,精度會逐漸降低。每當浮點數的 指數 增加(例如數值超過 2、4、8、16 等 2 的冪次),最小步進值就會 變大,導致精度損失。

實際上,這表示玩家越遠離世界原點(2D 遊戲為 Vector2(0, 0),3D 遊戲為 Vector3(0, 0, 0)),精度就會降低。

這種精度損失可能導致遠離世界原點的物件出現「抖動」現象,因為模型的位置會對齊到最接近的可表示浮點值。這同樣也會導致物理異常,只在玩家遠離世界原點時才會發生。

範圍決定了數值能儲存的最小與最大值。如果玩家嘗試超出這個範圍,將無法移動。不過,實際上通常會在達到極限範圍前,先遇到精度不足的問題。

範圍和精度(兩個指數區間間的最小步進)取決於浮點數型別。理論上,單精度浮點數能儲存極大的值,但精度非常低。實際上,無法表示所有整數的浮點數型別並不實用。在極端數值下,精度會低到連相鄰的兩個 整數 也無法區分。

以下是浮點數能夠精確表示所有整數值的範圍:

  • 單精度浮點數範圍(可表示所有整數): -16,777,216 到 16,777,216 之間

  • 雙精度浮點數範圍(可表示所有整數): -9 千兆 到 9 千兆之間

範圍

單精度步進

雙精度步進

註解

[1; 2]

~0.0000001

~1e-15

靠近 0.0 時精度更高(本表已簡化)。

[2; 4]

~0.0000002

~1e-15

[4; 8]

~0.0000005

~1e-15

[8; 16]

~0.000001

~1e-14

[16; 32]

~0.000002

~1e-14

[32; 64]

~0.000004

~1e-14

[64; 128]

~0.000008

~1e-13

[128; 256]

~0.000015

~1e-13

[256; 512]

~0.00003

~1e-13

[512; 1024]

~0.00006

~1e-12

[1024; 2048]

~0.0001

~1e-12

[2048; 4096]

~0.0002

~1e-12

第一人稱 3D 遊戲無算繪瑕疵或物理問題時的最大*建議*單精度範圍。

[4096; 8192]

~0.0005

~1e-12

第三人稱 3D 遊戲無算繪瑕疵或物理問題時的最大*建議*單精度範圍。

[8192; 16384]

~0.001

~1e-12

[16384; 32768]

~0.0019

~1e-11

俯視角 3D 遊戲無算繪瑕疵或物理問題時的最大*建議*單精度範圍。

[32768; 65536]

~0.0039

~1e-11

所有 3D 遊戲無算繪瑕疵或物理問題時的最大*建議*單精度範圍。超過此範圍時通常需要使用雙精度(大世界座標)。

[65536; 131072]

~0.0078

~1e-11

[131072; 262144]

~0.0156

~1e-10

> 262144

> ~0.0313

~1e-10(0.0000000001)

超過這個值後,雙精度仍然遠比單精度精確許多。

使用單精度浮點數雖可超過建議範圍,但會出現更多可見的繪圖瑕疵,也更容易發生物理異常(例如角色在某些方向無法直線行走)。

也參考

詳見 Demystifying Floating Point Precision 文章以獲得更多資訊。

大世界座標的運作方式

大世界座標(又稱 雙精度物理)會提升引擎內所有浮點計算的精度。

預設情況下,GDScript 的 float 是 64 位元,但 Vector2Vector3Vector4 僅為 32 位元。這表示向量型別的精度受限。為了解決這問題,可以提升 Vector 型別中浮點數的位元數。這會帶來 指數級 的精度提升,不只是兩倍,數值越大時提升幅度越大。從單精度提升到雙精度,最大可表示的數值也大幅增加。

為避免遠離世界原點時模型吸附問題,Godot 的 3D 繪圖引擎在啟用大世界座標時會提升繪圖精度。著色器為了效能考量不會用雙精度浮點數,但會用 替代方案 來用單精度浮點進行雙精度模擬。

備註

啟用大世界座標會增加效能與記憶體使用,特別是在 32 位元 CPU 上。請僅在真正需要時啟用。

本功能主要針對中高階桌面平台設計。大世界座標在低階行動裝置表現可能不佳,除非你另行降低 CPU 負載(如減少每秒物理更新次數)。

在低階平台上,可改採 原點平移(origin shifting) 方法來支援大世界,無需用到雙精度物理與繪圖。原點平移可用單精度浮點運作,但會帶來更多遊戲邏輯複雜度,特別是在多人遊戲下。因此本頁不詳述原點平移技術。

哪些情境需要用到大世界座標?

3D 太空或行星規模模擬遊戲通常會需要大世界座標。這也適用於同時需要支援 非常 快速移動、又偶爾需要極慢且精細移動的遊戲。

另一方面,僅在確實需要時才應使用大世界座標(為了效能)。大世界座標通常**不需要**以下情境:

  • 2D 遊戲,因為精度問題通常不明顯。

  • 小規模或中等規模世界的遊戲。

  • 有大世界但分為多個關卡、各關卡間有載入流程的遊戲。你可以讓每個關卡都以世界原點為中心,藉此避免精度問題且不會損失效能。

  • 開放世界遊戲的*可步行區域*未超過 8192×8192 公尺(以世界原點為中心)。如上表所示,即使是第一人稱遊戲,在這範圍內精度都還可接受。

如果有疑慮,你的專案多半不需要用到大世界座標。舉例來說,大多數現代 AAA 級開放世界遊戲都沒有用大世界座標系統,仍然用單精度浮點數來做繪圖與物理。

啟用大世界座標

你必須重新編譯編輯器與所有要用的匯出範本二進位檔。如果只打算用發行模式匯出專案,可以跳過除錯範本的編譯。不論如何,你需要編譯一次支援大精度的編輯器,這樣才能直接測試大世界座標,而不必每次都先匯出。

請參閱 編譯 章節以取得各平台的編譯說明。編譯編輯器與匯出範本時,需加上 precision=double SCons 選項。

產生的二進位檔會以 .double 為副檔名,以便和無副檔名的單精度二進位檔作區分。你可以在匯出對話框的專案匯出預設中指定這些二進位檔作為自訂匯出範本。

單精度與雙精度版本的相容性

使用 ResourceSaver 單例儲存 二進位 資源時,如果是用雙精度版本儲存,檔案內會標記特殊旗標。因此當你切換到雙精度版本並覆蓋儲存時,磁碟上的所有二進位資源都會被更新。

單精度與雙精度版本均可用 ResourceLoader 單例載入帶該旗標的資源。換句話說,單精度版本可載入雙精度版本儲存的資源,反之亦然。文字型資源不會存放雙精度旗標,因為它們不需要此旗標也能正確讀取。

已知不相容處

  • 在網路多人遊戲中,伺服器與所有用戶端都應使用相同的版本,以確保精度一致。混用不同版本 可能 可以運作,但會有各種問題風險。

  • 在雙精度版本中,GDExtension API 存在不相容的變更,這代表擴充套件**必須**重新編譯才能與雙精度版本相容。對擴充開發者而言,當用 precision=double 建置 GDExtension 時,會啟用 REAL_T_IS_DOUBLE 定義。此時 real_t 會對應單精度版的 float,雙精度版則對應 double

限制

由於 3D 繪圖著色器實際上未用雙精度浮點,因此 3D 繪圖精度仍有限制:

  • 三平面貼圖 不會受益於精度提升。遠離世界原點時,使用三平面貼圖的材質會有明顯抖動。

  • GPUParticles3D nodes with Local Coords disabled will not benefit from increased precision. This can cause visible particle snapping to occur when far away from the world origin. Nodes with Local Coords enabled, as well as CPUParticles3D nodes, will still benefit from increased precision.

  • Shaders using the skip_vertex_transform or world_vertex_coords render modes don't benefit from increased precision.

  • 在雙精度版本中,著色器 fragment() 函式內的世界座標無法從視角空間重建,例如:

    vec3 world = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
    

    改為在 vertex() 函式內計算世界座標,並用 varying 傳遞,例如:

    varying vec3 world;
    void vertex() {
        world = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
    }
    

目前 2D 繪圖在啟用大世界座標時無法受益於提升精度。這會導致遠離世界原點時(在常見縮放下,大約數百萬像素距離)模型吸附現象明顯。不過,2D 物理計算仍會受益於精度提升。