下一步:從哪裡接手

這份每輪重寫,不追加。 HANDOFF.md 說明現況與已排除的假設, 這一份說明下一輪先做什麼、為什麼是這個順序。最後一節是可直接貼進新對話的提示詞。

(前一版累積了三個「附錄:以上已過期」,那是追加而不是重寫的結果。 歷史都在 RE_NOTES_AVATAR.md §36~§46,這份只留現在該做的事。)


0. 三十秒摘要

除了彈簧骨物理與卡通渲染,其他都完成了:549 動作 + 20 相機 + 臉部 + 頭髮 已在 GLB 裡,Live2D 三次係數與 Bezier 轉檔已修(§43), 279 套服裝通用性已驗(§45),README 已更新(§46)。

彈簧骨誤差 110%(100% = 完全不做), ProcessDynamicBoneLayer 的子系統全部實作完了, 症狀收斂成單一項:過擺 1.50 倍,候選只剩「damping 的第二用途」與「風」。

驗收設施齊全 —— 每個假設都可以量,不必用推的


1. 先做這個:風(CalcWindPower

為什麼是它

windPower = 0.7開著的(§35 從遊戲讀出來的),但模擬完全沒實作。 它是唯一一個「遊戲有、我們沒有」的能量項,而剩下的症狀正是能量太多(過擺)。

§35 當時的判斷是「風會增加擺動、方向不對,先擱著」—— 那是在還有四個 bug 的模型上做的(§38 的限制鏡射、§39 的 delta、 §41 的 _ast、§42 的平滑都是之後才修的)。那個判斷不能算數,必須重測。

怎麼做

CalcWindPower(float3, ManagePropertyData ByRef, Single, Single) @ 0x02793194
呼叫點:newPos += rotate(CalcWindPower(…) × wind × 全域風強)

尚未逆向。先讀出簽章裡兩個 Single 是什麼(時間?相位?), 再決定實作。風若是週期性的,它同時是驅動源也是相位約束 —— 這比純阻尼更能解釋「過擺但時間資訊仍正確」。

怎麼判讀

四支工具一起看,不要只看百分比(理由見 §3):

結果 意義
過擺往 1.00x 掉且 k=0 仍是最佳 對了,繼續往精確係數走
過擺掉但 k=0 掉出最佳 --vel 同一種假象(§38),退回
過擺不動 風不是能量項,剩 damping 那條

需要跑遊戲的前置

風做下去之前要確認 run00 錄製當時場景的風向/風強。 若是 0,那 §35 讀到的 0.7 只是材質參數不是實際施加值,這條就直接結案。


2. 接著:damping 的第二個用途

目前 damping 只進 Verlet 慣性項 (1-damping)²。 重讀 0x02792f20 附近,確認它有沒有被用在別的地方。

已知的約束:--vel(力→速度→位置)能把過擺壓到 1.00x 但破壞時間資訊(§38)=> 阻尼不是那個形式。所以要找的是 「不引入一階延遲的耗散」,例如直接對位移量或對限制夾取後的殘差衰減。


3. 判準(重要,違反這條的結論一律不算)

不要只看誤差百分比。 §37 證明舊的 142% 落在「時間亂序帶」內 —— 分辨不出模擬與它自己的隨機平移版。四支工具要一起看:

scripts/diag_swing_trace.py   單根骨逐尤拉分量 + 平移對照組   <- 解析度最高
scripts/diag_swing_align.py   k=0 是否為最佳位移              <- 有沒有時間資訊
scripts/diag_swing_error.py   軸夾角(雜訊底線 ±13°)
compare_swing.py              誤差% + 過擺倍率

一個機制若讓 k=0 掉出最佳,誤差百分比再好看都是退步。


4. 與彈簧骨獨立、可以平行做的線

4.1 描邊 pass 與 stencil(卡通渲染唯一剩下的缺口)

251 個 metallib 已拆好、Metal Toolchain 已裝,render_sheet.py 可做渲染驗收。 未解的具體項目(§29/§33):_DefMap 各通道的完整語意、描邊 pass、 _StencilRef=64 出現在哪個 pass、描邊外推量。

注意:mos9527 那邊頂點色 R = 描邊遮罩,我們這邊 R 是「下半身、48 的倍數的 離散等級」—— 形狀像分區索引或描邊寬度等級,但不能直接套用他的結論(§25)。

4.2 阻尼解出來之後要一起做的收尾

--delta-current(§39)與 --quartz(§41)都忠於遊戲、都讓百分比變差, 原因相同:下游缺阻尼,正確的輸入反而被懲罰。兩個要一起翻成預設, 判準用 §39 的分組表與 §37 的對齊掃描,不是總體百分比。

4.3 QuartzDriver 參考骨的延遲(需要跑遊戲)

直接比對說 lag=1、下游看說 lag=0,兩個量測不一致(§41)。 把大腿_ast 錄進同一個 run 即可釘死(agent.bakeSwing 走 Transform 階層找骨,加幾個骨名)。與 §1 的風一起在同一次進遊戲做掉。


5. 不要做的事

  • 不要在沒有對照組的情況下「N 個選項挑最小」。 有雜訊時那個程序必然 回傳一個贏家,而贏家不是證據。§43 的子步數掃描就是靠「不是單調關係」 才判定它不是答案,不是靠「哪個最小」。
  • 不要用總體中位數判斷某個機制有沒有效。 局部 76° 的變化會被彙總指標吃掉。
  • 不要重做 HANDOFF.md §2.3 表上那十項。 每一項都有量測與章節出處。
  • 不要把 _avatar/baked*.jsondriven_*.json 當可信輸入。 那是中間產物, 現行資料版本見 HANDOFF.md §4。

6. 提示詞(直接貼進新對話)

接手一個 Unity 手遊資產逆向專案。請先讀這三份,順序照列:

  ClaudeDocs/NEXT_STEPS.md      <- 從這裡開始,講下一步做什麼
  ClaudeDocs/HANDOFF.md         <- 現況、已排除的假設、踩過的坑
  ClaudeDocs/RE_NOTES_AVATAR.md <- 主要來源,§1~§46
                                    先 grep '^## ' 看章節,不要整份讀

檔案索引在 ClaudeDocs/INDEX.md。

專案有一組從這些筆記提煉的 skills(.claude/skills/ 是領域專用,
~/.claude/skills/ 是通用),其中 verify-before-believe、ground-truth-harness、
fan-out-and-prune、notes 直接適用於這輪的工作,請在對應時機使用。

第一件事做 NEXT_STEPS.md §1:逆向 CalcWindPower @ 0x02793194
(windPower=0.7 是開著的但完全沒實作,是唯一「遊戲有我們沒有」的能量項),
實作進 sim_swing.py,然後四支診斷工具一起量,回報過擺倍率、軸夾角、
k=0 的排名,不要只回報誤差百分比。

工作方式的三個要求:

1. 每個假設都用量的,不要用推理走到結論。
   基準線 110% 誤差 / 1.50x 過擺 / 55.9° 軸夾角 / k=0 排名 2/90。
2. 效應小於 2 倍時要有對照組,並說明雜訊底線是多少。
   軸夾角的雜訊底線是 ±13°。
3. 失敗與更正寫進 RE_NOTES_AVATAR.md 的新章節(接 §47),不要覆蓋舊結論;
   HANDOFF.md 與 NEXT_STEPS.md 是重寫不是追加。

只想做渲染那條(不碰彈簧骨)的話,把第一件事換成:

第一件事做 NEXT_STEPS.md §4.1:描邊 pass 與 stencil。
251 個 metallib 已拆在 _avatar/shader/(Metal Toolchain 已裝),
render_sheet.py 可做逐像素渲染驗收。
未解項目:_DefMap 各通道語意、描邊 pass、_StencilRef=64 在哪個 pass、
描邊外推量。注意不要套用 mos9527 的通道結論(§25 已證明約定不同)。

在 SiaoHub 檢視原始檔