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°,偏航峰值航向跟著移動,幅度不變。
讀回結果把原因定位如下:
- 正式 wasm 建置沒有開上游的
block-solverfeature。Simplified(twist)路徑的 normal 約束是逐點 Gauss–Seidel,順序就是 manifold 排序後的順序。 - 輪地接觸幾乎都是 2 點,沿輪寬分開 9–11 mm。地面是 collider1,所以排序基底
local_n1等於世界座標。 - 逐點求解時,先解的點固定拿走約 62% 的負載。沿世界 X 排序時,左右輪先解的點互為鏡像相反,於是形成淨偏航力矩。方向隨世界航向改變;沿 ±X 時排序鍵接近並列,偏差趨近 0。
- 對調求解順序後,衝量分配與偏航同時變號。改用精確 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-solverfeature:風險面過大(結構欄位、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:退回原逐點。
- 一點未作用(單點 lane),或
- 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_CURRENTdigest。 - golden 與 conformance 重基線。
- canon:physics-engine.md、protocol.md、testing.md、版本規範.md;
編輯器操作.md與建模參數/零件與共用介面.md的輪類段提醒作者:非圓輪(方、六角、星形等)的接地點隨滾動變化,偏航屬造型本身的混沌,本決策不保證改善。 - 實作與 001082(動態薄目標穿透)同一 repair 代進行,wasm 只換一次。
- pinning 的 vendored 版本值同步需另行取得同意(比照 001057)。