Resident ready Static companion
kari_mikumao Lab

Physics

WMMD physics: three backends behind one interface

Bullet as the MMD-faithful reference, a pure-Rust fallback, a clean-room PGS solver, and an XPBD cloth engine - swappable at compile time.

  • wmmd
  • physics
  • bullet
  • xpbd

MMD physics is a compatibility problem before it is a simulation problem.

Spring bones, rigid bodies, and joints authored for the original tool have expected behavior. If my renderer simulates correctly but differently, it still looks wrong to the person who made the model. And they are right - their rig is the spec, not my solver.

So WMMD keeps several backends behind one interface, and treats one of them as the reference.

The Backends

All four live behind Cargo features on wmmd-runtime, so a host picks its tradeoff at compile time:

  • Bullet (default) - MMD-faithful reference behavior, reached through a thin C shim over Bullet3 in crates/wmmd-bullet-sys. It builds vendored sources, so it costs a cmake and a C++17 toolchain at build time.
  • Native Rust - a built-in backend that needs no cmake, for environments where the C++ build is not worth it.
  • Native PGS - a clean-room Havok-style projected Gauss-Seidel solver with Baumgarte stabilization.
  • Loom - an experimental XPBD engine aimed at cloth and hair.

Having a reference implementation turned out to matter more than having the fastest one.

When a rig behaves oddly under an alternative solver, Bullet’s result is the arbiter. The question becomes “why does this backend disagree” instead of “which of these is right.” The second question has no answer and eats entire evenings.

What the Runtime Owns

The physics module sits inside wmmd-runtime alongside the IK solver and the PhysicsController, including PMX spring constraints across the format’s three modes.

The runtime is CPU-only and file-free by invariant. It receives already-parsed assets and steps simulation, bone transforms, and IK in one update() call driven by the host’s frame time.

Physics can be paused, resumed, reset, and staged through the same command queue that adds models. That sounds like a small detail, but in an editor it is the difference between guessing and diagnosing - if you can freeze a rig and re-run it, you can actually see what it is doing.

The IK solver supports VMD IK on/off tracks, so motions that deliberately disable IK for part of a sequence play back as authored instead of being silently overridden.

How I Check It

Physics correctness is not eyeballed. The tooling crate carries a physics verifier alongside the snapshot runner.

The working rule for the whole engine is that a fix has to generalize. Reproduce with whatever model exposed the problem, then write the fix and its test in general terms - arbitrary bone counts, morph sets, material configurations, rig layouts. Never as a special case for one file.