Appearance
旧城拆迁
背景:XPBD(TS) 布料引擎已运行数周,但维护成本高、与 WASM Bullet 物理栈重复。ADR-081 决策全栈移除 XPBD,布料物理统一收归 WASM Bullet。 过程:删除 XPBD 求解器 + 碰撞器 → 物理桥接层重构 → 虚拟裙骨(ADR-084)补位 → 风场注入(wind-physics.ts)→ 滑块防抖保留。
序、一张要拆的城
王逸打开 src/physics/ 目录。
十二个文件。XPBD 求解器、碰撞器、约束求解器、粒子系统——一共 3000 多行 TypeScript。
这是他亲手造的城。
现在要拆。
一、拆迁令
ADR-081 的决策文档标题是「移除 XPBD(TS) 布料引擎」。
核心理由:两套物理引擎并存。MMD 模型自带 WASM Bullet,布料用 XPBD。两套碰撞检测、两套步进逻辑、两套 UI 集成。维护成本是双倍的,性能也是双倍的差——XPBD 在 TS 层跑,WASM Bullet 在 C++ 层跑,同样的布料,WASM 版本快三到五倍。
babylon-mmd 的 public API 已经够用了。addRigidBody、addConstraint、removeRigidBody、removeConstraint——全 public,不需要 fork,不需要 hack。
XPBD 是一座过渡期的城。城建好时,地基已经换了。
二、拆除
王逸开始删除文件。
第一个:xpbd-solver.ts。1200 行。求解器的核心——位置修正、速度修正、约束投影。
第二个:xpbd-collider.ts。400 行。SDF 碰撞器——胶囊体、球体、地面碰撞。
每删除一个文件,跑一遍 npx vite build。TypeScript 编译器会告诉他,有没有地方还引用着这些死去的代码。
红色错误。xpbd-solver 被 scene.ts 引用。删掉那行 import。
红色错误。xpbd-collider 被 scene-menu.ts 引用。删掉整个 buildPhysicsLevel() 函数。
红色错误。DEFAULT_BODY_CAPSULES 被 outfit.ts 引用。改成 WASM Bullet 的碰撞体配置。
两个小时后,编译通过了。
src/physics/ 目录只剩下两个文件:physics-bridge.ts 和 wind-physics.ts。
城拆完了。月台还在。
三、虚拟裙骨
大多数 PMX 模型没有裙骨。WASM Bullet 的布料是骨骼级的——它需要一根根骨骼,每根骨骼挂一个刚体,刚体之间用弹簧约束连接。
没有裙骨的模型,WASM Bullet 就不知道裙子在哪。
王逸在 src/scene/physics/ 下新建了两个文件:skirt-analyzer.ts 和 virtual-skirt.ts。
skirt-analyzer.ts 的职责:给定一个 PMX 模型,分析它的顶点分布,找到"裙摆区域"。从腰骨往下,0.3m 到 0.8m 范围内的顶点,按径向角度分组,每组生成一根虚拟骨骼。
这不是精确的裙子识别。穿裤子的模型,裤腿的顶点密度也会高。但 MVP 阶段够用——穿长裙的漏掉一点,穿短裙的漏掉一点。完美的方案需要从骨骼层次结构动态推断,但那太复杂了。
virtual-skirt.ts 的职责:把分析出的虚拟骨骼注入 WASM Bullet 物理世界。为每根虚拟骨骼创建一个 MmdWasmPhysicsRigidBody,在相邻骨骼之间创建弹簧约束,调用 addRigidBody() 和 addConstraint() 注入。
四、风
风场还没接上。
wind-physics.ts 是从 XPBD 时代保留下来的,但它的实现依赖 XPBD 的粒子系统。现在 XPBD 删除了,风场需要重新接入 WASM Bullet。
注入方式变了。XPBD 时代,风力直接作用在粒子上。WASM Bullet 时代,风力作用在刚体上——刚体有质量、有惯性,同样的力产生的加速度更小。
风力系数从 0.05 调到 0.15。
五、防抖
王逸拖动滑块时,裙摆又开始闪烁。
老问题。滑块每移动一个像素,回调就触发一次,布料就销毁一次、重建一次。
XPBD 时代,防抖时间是 100ms。WASM Bullet 时代,重建开销更大——刚体、弹簧约束、物理世界注入——防抖时间调到 200ms。
九行代码。一个计时器。没动引擎,没动网格结构,没动约束求解器。
尾声
王逸提交了代码。
布料之魂没有消失。它只是换了一座城——从 XPBD 的小城,搬到了 WASM Bullet 的大城。
城变大了,街道变宽了。但灵魂还在。那条能让裙摆随风飘动的裙子。