Skip to content

物理系统

一句话总览

three 官方 MMDPhysics.js(Ammo.js / Bullet wasm 后端)+ 运行时参数调校

没有自研物理内核——所有"手感"来自对 Bullet 刚体/约束参数的二次调校(重力、风力、约束松绑)。

参数面板(PHYS)

所有参数在 PHYS 面板实时可调,支持 localStorage 持久化。

基本参数

参数默认说明
enabled物理总开关
gravity1.0全局重力倍率
sway待机摇摆(根骨骼正弦摆动)
amp0.06摇摆幅度
speed1.0摇摆速度
fpsCap0帧率上限(0=不限)
autoRotate相机自动环绕
debug刚体线框可视化

风力系统

参数默认说明
windOn风力总开关
wind0.12风力强度
windAuto自动风向(0°~360° 循环扫动)
windAngle手动风向(关闭 windAuto 时生效)

TIP

风向罗盘 + 3D 场景中的箭头实时同步,0°=朝观众方向,顺时针旋转。

三个核心调校(缺一不可)

① 配件微重力

头发/领带刚体只有 15% 重力,裙子 30%。原因是 PMX 模型的头发刚体质量远大于裙子,Bullet 默认重力会把卷发拉直。

② 裙摆/袖口约束松绑

Sour 式裙子约束被作者焊死(旋转限制 ±1.1°),运行时重设为:

  • 裙子:旋转限制 ×4、旋转弹簧 ×0.25、位置弹簧 ×0.1
  • 袖子:旋转限制 ×3、旋转弹簧 ×0.5、位置弹簧 ×0.5

③ 风只吹头发/领带(防走光)

风力正则排除了裙子和袖子,它们只靠约束松绑后的惯性摆动。这是刻意设计——裙摆被风吹起会走光。

踩坑记录

CAUTION

以下是历次调参踩过的坑,改参数前必读。

#结论
1弹簧刚度 ×2 反而更糟非线性,调手感走重力/风力路线
2setDamping 甩动更大弹簧相关参数维持模型原始值
3"头发拉长"不是位移问题是旋转累积把卷发甩直(伸直比 0.906→0.942)
4ammo.wasm.js 是精简构建getCollisionObjectArray(),释放必须逐个 destroy
5Ammo 异步加载模块顶层禁止 new Ammo.btVector3(...)
6mmd-parser morph bug类型 4~7 和 9 不消费字节,新模型需验证
7dt 必须限幅 1/30后台切回/掉帧时大步长让 Bullet 爆炸
8摇摆只摇安全骨骼有 type1/2 刚体的骨骼会被物理回写覆盖

技术架构

点击展开(开发者阅读)

每帧流程(顺序不能乱)

动作/待机摇摆 → 微风施力 applyWind(t) → mesh.updateMatrixWorld(true) → physics.update(dt)

关键约束

  • updateMatrixWorld(true) 必须在 physics.update 前:MMDPhysics 读 bone.matrixWorld 驱动 kinematic 刚体
  • warmup(60) 创建后立即执行:让裙摆/头发落定
  • 单位制:MMD 1 单位 = 10cm,重力 (0, -98, 0)

必须保留的设计

  • unitStep: 1/65, maxStepNum: 3
  • 配件微重力 / 约束松绑 / 风豁免三件套
  • 模型切换完整释放(Ammo 对象 + GPU 资源)
  • 风向罗盘 + 3D 箭头共用 getWindAngle(t) 单一来源

基于 Three.js + Ammo.js · AGPLv3