Symptoms
- [Stretch Explosion] When dragging/moving the model, clothes and hair lag and elongate, getting pulled into noodles or spikes.
- [Rotation Tearing] When rapidly rotating the model (washing machine effect), clothes instantly explode and become misaligned due to the extreme centrifugal force.
- [Trebuchet Effect] When loading extremely fast VMD dance motions, clothes instantly collapse and fly around as if flung out by a trebuchet.
- [Lying Flat Collapse] When the character lies flat or stands upside down, limited by the original outward one-way joint constraints, clothes undergo inward crushing oscillation.
- [Freeze/Deadlock] When there are many clothes/hair (high bone density), the browser instantly freezes for several seconds, and the frame rate plummets.
Root Causes and Solutions
1. Mode 2 Spatial Anchor Tearing and Failure to Return
- Problem: Originally, to prevent Mode 2 from being
setWorldTransformviolently aligned and pulled into spikes, it was forcibly downgraded to Mode 1. But the rigid body corresponding to Mode 2 (such as the hair root) itself has no spring connecting it to the body! After downgrading, it loses its fixed anchor point, is only pulled down by gravity, and can never return after the motion ends. - Solution: Undo the downgrade and correctly implement Mode 2 kinematic synchronization. Not only should it not be downgraded, but you should instead rely on Ammo.js's most standard
setCenterOfMassTransformand synchronize the Motion State to perform tear-free center reset. Also addbody.setActivationState(4)to completely disable sleeping, preventing rigid bodies from being frozen by the algorithm when the motion is stationary and being unable to return.
2. "Ghost Penetration" of the Human Body Collision Anti-Collision Layer
- Problem: Although
scalepreserves the largest body shield, during high-speed dancing, clothes still pass through the human body without damage. The reason is that the_setTransformFromBoneresponsible for synchronizing the skeletal torso (Mode 0) incorrectly usessetWorldTransform(), which in the physics engine is equivalent to "teleport-resetting every frame," causing the torso rigid body to have no continuous motion state and thus no impact momentum feedback inside Bullet. - Solution: MotionState Sync. Remove the pure
setWorldTransformand replace it with dedicated feeding ofbody.getMotionState().setWorldTransform(). Bullet will, in the underlyingstepSimulation, automatically derive and calculate extremely precise high-speed inward kinetic energy based on comparison with the previous frame and activate ballistic knockback feedback! Completely break ghost clipping.
3. High-Speed Trebuchet Effect Triggered by VMD Teleport Jumps
- Problem: During high-speed VMD motions or even instantaneous dodges, long-distance displacement occurs between bones. At this time, spring force accumulates infinitely and, in the next step, launches the cloth/hair vertices bound to it at supersonic speed.
- Solution: Velocity Limiter. At the final stage of
update(delta), iterate through dynamic rigid bodies. IfLinearVelocity(>50.0) orAngularVelocity(>30.0) is found to exceed the normal physical spatial speed limit, forcibly normalize and reduce the vector proportionally. This does not change the direction of the kinetic energy trajectory, yet like a parachute, it strangles the momentum of "supersonic" chaotic flying.
4. Gravity Dead-Angle Compression Caused by Non-Upright Angles
- Problem: MMD's global gravity is always vertically downward. When a person lies flat, gravity is equivalent to pressing the skirt straight toward the chest. This violates the original extremely narrow inward-facing joint anti-clipping clearance, causing an unsolvable collision deadlock.
- Solution: Local Relative Gravity & Local Floor (Local Gravity & Floor). Convert the global vertical gravity through
quaternioninto a "local toward-feet" gravity that conforms to the body; at the same time, abandon the horizontal stationary void ground, and let the rotation matrix of the supporting floor be directly bound to the connectedmesh.quaternion. When the character lies flat, the ground instantly transforms into a vertical wall pressed against the back.
5. Spontaneous Overlap and Piercing of High-Density Rigid Bodies
- Problem: After the number of physics iterations is lowered, the engine no longer has the computational power to separate rigid body arrays that are interlocked with each other. At startup, they will self-detonate due to physical overlap repulsion.
- Solution: Differentiated Shields and High-Density Specialization。
- Spring Alloying: Pull ERP (error correction restoration) to 0.8, increase Stiffness by 2.5 times, providing devastating original-shape restoration capability.
- Dynamic Pressure Relief Valve: Adjust CFM to 0.015, leaving a tiny deformation margin for originally absolutely rigid joints, unloading extreme torque.
- Differentiated Body Shield: The body rigid body (Mode 0) always maintains
scale = 1.0andmargin = 0.05thick heavy anti-collision shield; clothing/hair rigid bodies shrink to0.9volume and ultra-thinmargin = 0.01. This creates an absolute complementary structure of "barrier and gossamer", preventing mutual interlocking.
6. Bullet / WebAssembly Low-Level Engineering Pitfalls
- Problem 1 (WASM Memory Leak): In a loop, you cannot directly feed
new Ammo.btVector3()to interfaces involving gravity; GC cannot reclaim the underlying C++ heap space, causing second-level OOM freeze.Solution: Mount a singleton vector inside the class and repeatedlysetValue()。 - Problem 2 (Static Plane Failure):
btStaticPlaneShapedoes not support a real-time center transformation system (does not support flip rotation), and using it as a floor will cause fault piercing.Solution: Use an extremely large thinbtBoxShape(100x1x100) and move the Origin Y-axis down by 1 unit as a substitute.
Key Experience
Do not fight the physics engine's iteration computational power head-on! When facing Ammo.js (Bullet) with hundreds of high-density models with joint constraints, directly increasing numIterations to 100 will completely ruin the browser's single-threaded 60FPS.The most efficient dimensional strike is definitely to convert physics into pure code-space constraints (locking, downgrading, co-moving, speed limiting)!