Skip to content

状态: 🟢 已修复

日期: 2026-07-18 严重程度: 🔴 P1 影响范围: frontend/src/proc-motion-bridge.ts发现方式: 用户反馈 修复方案: updateProcMotion() 中 hasUserVmd 判定改为基于 vmdPath 而非 vmdData,消除程序化动作与用户 VMD 的误判(关联 ADR-129)

程序化动作应用到角色无效(动作1 / 基础槽位)

  • 状态:已修复
  • 关联:ADR-129(场景级动作 UI + 双槽位)、proc-motion-bridge.ts
  • 发现:2026-07-18

现象

在角色动作菜单将「动作1(基础)」设为程序化(待机呼吸 / 自动舞蹈)后,角色仅短暂抖动即回到静止,程序化动作不生效。

根因

ADR-129 per-slot 重构后,proc-motion-bridge.tsstartProcMotion 改为将生成的程序化 VMD 写入 inst.vmdData(替代旧的直写 setRuntimeAnimation 路径),并显式把 inst.vmdPathnull

updateProcMotion()scene.ts:446onBeforeRenderObservable每帧调用,其内部用 model?.vmdData !== null 判定"用户 / 场景 VMD 是否存在"。由于程序化数据也存于 vmdData, 每帧都被误判为"用户 VMD 已存在",于是执行 stopProcMotion() 清空 vmdData → 下一帧角色归零。

焦点模型在 onBeforeRender 每帧都会被重判,因此动作1(基础槽位)程序化在首帧后即被停掉。

修复

proc-motion-bridge.ts:265

ts
// 修复前
const hasUserVmd = model?.vmdData !== null && model?.vmdData !== undefined;
// 修复后
const hasUserVmd = !!model?.vmdPath;

判别"用户 / 场景 VMD"的可靠依据是 inst.vmdPath

  • 程序化动作 vmdPath 恒为 null(startProcMotion 显式置空);
  • 用户 / 场景 VMD 必有非空 vmdPath(applyIntentToModel / loadVMDFromPath 写入)。

该口径与 stopProcMotionuserVmdPresent 判定一致,消除误判。

验证

  • npm run build(tsc + vite)exit 0(365 模块)。
  • proc-motion-bridge.test.ts 73/73(新增 2 项回归测试)、playback.test.ts 31/31、procedural-motion.test.ts 40/40 全过。
  • 行为不变性:无 VMD → 自动待机;用户 / 场景 VMD 存在 → 优先于程序化(安全网分支仍生效)。