跳轉到

D-20261027-01|接觸點求解順序對稱化

背景與驅動力

無輸入直行的公版車會偏航,偏航方向取決於車頭的世界朝向(issue 001075)。在現行 TM 核心(f2afeeba)上,以合成平地、每 15° 一個航向量 20 秒:

  • 漂移是等速線性,不是發散。
  • 航向依存的一次諧波幅:heavy 約 2.2°、control 約 4.1°、speed 約 1.6°;speed 另有偶發跳變。
  • 車速有 −Z 分量時偏正、有 +Z 分量時偏負,沿 ±X 時接近 0。
  • 4 m 寬的走廊裡,這樣的偏航看得出來;偏向取決於場地朝向,屬於公平性問題。

原先懷疑摩擦切向基底綁世界軸,歸因實驗否定了這一點:

  • 切向基底繞法線轉 37° 或 90°,型態與幅度都不變。中心摩擦本來就是耦合 2×2 求解加圓錐投影,對平面內旋轉不變。
  • 關掉 gyroscopic 也不變。
  • 只轉 manifold 排序基底 37° 或 90°,偏航峰值航向跟著移動,幅度不變。

讀回結果把原因定位如下:

  1. 正式 wasm 建置沒有開上游的 block-solver feature。Simplified(twist)路徑的 normal 約束是逐點 Gauss–Seidel,順序就是 manifold 排序後的順序。
  2. 輪地接觸幾乎都是 2 點,沿輪寬分開 9–11 mm。地面是 collider1,所以排序基底 local_n1 等於世界座標。
  3. 逐點求解時,先解的點固定拿走約 62% 的負載。沿世界 X 排序時,左右輪先解的點互為鏡像相反,於是形成淨偏航力矩。方向隨世界航向改變;沿 ±X 時排序鍵接近並列,偏差趨近 0。
  4. 對調求解順序後,衝量分配與偏航同時變號。改用精確 2×2 求解或兩順序平均後,分配回到約 50/50。

根因:接觸點的求解順序由綁世界軸的排序決定,加上逐點 Gauss–Seidel 的順序偏差,使同一 manifold 內的負載分配依世界朝向而變。

3–4 點接觸的頻率:

對象 3–4 點占比
公版輪地 0–9%
UGC 原生案例:底盤平貼、拖曳或雪橇型武器滑行 約 16–34%
UGC 原生案例:方塊、薄刀片、彈體 大多為 4 點

UGC 拖曳武器(4 點滑行)在只處理 2 點時,航向依存仍有 0.55°。

考慮過的選項

  • 維持現狀:偏航依場地朝向而定。否決。
  • 摩擦切向基底對齊滑移方向或輪軸:實測與偏航無關。否決。
  • 圓錐投影:現況已經是耦合 2×2 加 simd_cap_magnitude。不需要改。
  • 改從能量來源下手(陀螺或鉸接耦合):關掉 gyroscopic 沒有變化。否決。
  • 整個開啟上游 block-solver feature:風險面過大(結構欄位、coulomb 與 generic 路徑都改變,上游記錄 3D 有抖動)。不採用,只在 twist 路徑套用同一個 MLCP。
  • 排序鍵改為與世界無關、左右對稱的定義:輪胎的 COM 在兩點中間上方,排序鍵會並列;而且只能讓偏向不依世界方向,順序偏差本身仍在。否決。
  • BLK:只處理 2 點(精確 2×2 MLCP):
  • 公版改善:heavy 一次諧波 2.20→0.02°、control 4.09→0.37°、speed 1.63→1.20°。
  • UGC 拖曳武器 0.65→0.55°,幾乎沒改善。
  • 完賽 124/270。
  • 被 BLKS 取代。
  • BLKP:2 點精確,3–4 點兩兩成對精確 block((0,1)、(2,3)):
  • 拖曳武器 0.65→0.02°。
  • 但成對之間仍有順序,殘留與航向無關的固定偏向 −0.11°;六角輪平均偏航變差(17.9→27.9°)。
  • 不採用。
  • BLKF:BLK 只套用在一側為固定剛體的接觸:所有量測都與 BLK 相同,沒有額外好處。不採用。
  • BLKS:2 點用精確 2×2 MLCP;3 點以上用正序與反序逐點結果的平均:採納。
  • 拖曳武器 0.65→0.02°、雪橇 0.64→0.003°、低底盤 →0。
  • 公版:heavy 0.16°、control 0.21°、speed 1.10°;speed 最大偏航 13.4→5.4°。
  • 完賽 133/270,所有變體中最高。

決定

  • 在 Simplified(twist)接觸約束的 normal 求解中,逐個 SIMD lane(一個 manifold)依作用點分類:
  • 2 點 lane:用上游 block-solver 的精確 2×2 MLCP,帶 per-point cfm,依序檢查四個候選。
    • 一點未作用(單點 lane),或 det ≤ 0.01·k'11·k'22:退回原逐點。
  • 3 點以上的 manifold:從同一個起始速度分別做正序與反序的逐點求解,各點衝量取兩者的平均,再一次套用差量。
  • 分類只看該 lane 自己的作用點,與同一 SIMD chunk 的其他 manifold 無關。
  • 套用範圍:
  • biased 與 relax(wo_bias)兩種 pass 都經過 ContactWithTwistFriction::solve。稽核確認新規則已涵蓋兩者。
  • warmstart(各點加總)、update、refresh_rhs_wo_bias(各點獨立)與順序無關,不需要改。
  • apply_restitution(反彈)原為逐點依序,一併套用同一規則(2 點精確 2×2、3 點以上正反兩序取平均), 保持所有 normal 求解路徑與順序無關。反彈的作用點另需通過原有的反彈資格閘。
  • 共識設定:比照 D-20261026-02,用 world 的不可變整合參數承載,例如 contact_normal_order_policy(0=逐點、1=本決策),由 physics-version 釘住的 protocol 常數 PHYSICS_CONTACT_NORMAL_ORDER_POLICY = 1 指定。
  • snapshot、immutable world config 與 restore 都要驗證,有差異就原子拒絕。
  • 不得用 thread-local 或任何不進快照的狀態。研究原型用的是全域 atomic,正式化時必須改掉。
  • 門檻 0.01 與「3 點以上取正反序平均」都是 kernel 內固定規則,由 physics-version 釘住,不開放治理調整。
  • vendor:建立新的 repair 代,父代為 f2afeeba(TM+001049)代,並重建 wasm。設定為 0 時,步進軌跡必須與父代逐位元相同(研究原型已驗證)。

後果與影響

數字取自 friction 研究;正式核心為 TM,候選為 BLKS(研究 wasm d9a58833)。

  • 玩家可見(公版平地 24 航向 × 20 s):
指標 heavy control speed
航向依存一次諧波幅 2.20→0.16° 4.09→0.21° 1.63→1.10°
|偏航| 平均 1.69→0.41° 3.37→0.78° 2.61→1.56°
最大偏航 — — 13.4→5.4°

起步四向偏差不變,由 001085 處理。

  • UGC(原生,10 s 直行 × 8 航向,航向依存一次諧波幅):
造型 TM → BLKS
圓輪 0.41→0.01°
拖曳武器 0.65→0.02°
雪橇 0.64→0.003°
低底盤 已接近 0
  • 六角輪本身就混沌(偏航 17–28°),各變體都無法改善;BLKS 的平均值略差,屬混沌波動。
  • 非圓輪截斷、沉入,以及武器與底盤落地:沒有系統性變化。

  • 完賽率(三車三場 30 起跑):

  • TM 120/270(掉頭 16、翻覆 27);BLK 124/270(掉頭 14、翻覆 26);BLKS 133/270(掉頭 20、翻覆 22)。
  • heavy jungle 9→15、speed snowy 18→23。
  • 仍需另外進行數值重校。

  • 成本:

  • 八車 jungle,串行、量測前 CPU 5–9%,P50/P95 ms:TM 32.3–34.9/87.0–94.7(四趟);BLK 38.2–38.5/111.4–116.0(六趟);BLKS 33.4–33.8/98.5–100.2(兩趟)。
  • 拒絕幀 TM 241、BLK 328、BLKS 267,每趟都相同(決定性)。
  • 歸因:拒絕幾乎全是旋轉位移品質(rot),TM 229 幀、BLK 310 幀。被拒絕的幀約 60% 有車貼著陡面,主要是 Cliff_Left/Cliff_Right(node 19/20)與 Rail_Bend1(node 91)。
  • 位於 001084 的 17.0 m 卡點附近的車幀數:TM 192、BLK 595。
  • 結論:成本上升來自「卡在 001084 熱點、貼著崖面的車變多」,是軌跡改變造成的,不是求解器本身變貴。 jungle 卡點本身另行調查(issue 001084),不在本決策範圍。
  • snowy、urban 的 BLK 成本與 TM 持平或較低。BLKS 求解 3 點以上時,normal 部分約為原本的 2 倍,但對 jungle 整體成本影響已包含在上面的量測中。
  • 決定性:
  • 研究原型開關關閉時與正式核心逐位元相同(航向 9/9、完賽 eq 2/2)。
  • BLK 與 BLKS:串行對並行全同(航向 9+3、完賽 2);UGC 原生 410 案兩趟全同。
  • 軌跡全部改變:determinism golden 升 revision,conformance physics/track-entity-snapshot 的 snapshotSha256 會改。
  • Node 與 Chromium 核對後,再依 CI 矩陣跑其他瀏覽器與 OS。
  • 浮點:只用加減乘除、simd_inv 與乘 0.5,不引入 sqrt、atan2 或超越函數,跨平台風險與現行 normal 求解相同。
  • 品質閘:001081 C 弧牆絕對判準窗長(6 格):
變體 窗長 通過
TM 0/0/0/0/1/0 0/6
BLK 0/0/25/1/0/25 2/6
BLKS 0/8/5/44/0/0 1/6

略有改善,但沒有解決,仍交給 001051。

  • 既有缺陷 001082(彈打 2 mm 動態側護板,7 個起點微擾 × 30/60/120 m/s):

    註(2026-10-27):下表為舊判準(範圍過寬、只看越過板前平面)的數字,事後確認屬量測誤判;以幀末真實穿入與 嚴格穿過量測時,F/TM/BLK/BLKS 真穿過皆 0。001082 真缺陷改為 TM 帶入的旋轉薄件穿透動態薄目標,由 D-20261027-02(DA)處理,與本決策同一 repair 代實作。

變體 穿過次數(30/60/120 m/s)
F 7/7/7
TM 2/5/5
BLK、BLKP、BLKS、BLKF 7/7/7
  • TM 在 60、120 m/s 的「未穿過」格,最大穿入仍有 0.27–0.41 m,其實已飛越護板。
  • 30 m/s 的 5/7 擋下非常脆弱:只要在落定段或彈射段其中一段改用 BLK,就變成 7/7 與 6/7 穿過。
  • 判定:本決策沒有引入新的穿透機制,但讓 TM 偶然擋下的情況消失。001082 必須另行修正,不得以本決策的結果作為放寬理由。
  • 資產:PhysicsManifest 沒有相關欄位,公版零件與場地的 bytes、manifest digest 都不變。
  • 範圍:
  • vendor:contact_with_twist_friction.rs 的 solve() normal 迴圈(正式源約 1312 行)、整合參數、序列化與 restore 驗證、binding。
  • wasm 重建,換 RAPIER_VERSION_CURRENT digest。
  • golden 與 conformance 重基線。
  • canon:physics-engine.md、protocol.md、testing.md、版本規範.md;編輯器操作.md 與 建模參數/零件與共用介面.md 的輪類段提醒作者:非圓輪(方、六角、星形等)的接地點隨滾動變化,偏航屬造型本身的混沌,本決策不保證改善。
  • 實作與 001082(動態薄目標穿透)同一 repair 代進行,wasm 只換一次。
  • pinning 的 vendored 版本值同步需另行取得同意(比照 001057)。