[In this reprinted #altdevblogaday in-depth piece, BitSquid co-founder Niklas Frykholm looks at preserving the momentum of animated objects, and then applying them to ragdolls.] After a slew of abstract articles about C++ and code structuring, I'd like to get back to some more meaty game engine stuff. So today I'll talk about ragdolls. In particular, how to preserve the momentum of animated objects, so that when you switch over to the ragdoll it continues to stumble forward in the same direction that the animation was moving, before crashing to a gruesome death.
So this is a small, but important problem. We want to somehow get the velocities of the animated objects, and then apply them to the bodies in the ragdoll. The only snag is that animated objects typically don't know anything about velocities. Also, we need some way of matching up the physics bodies with the animated objects. First, some background information. In the Bitsquid engine, physics, scene graph, and animation are completely separate systems. We strongly believe in minimizing the couplings between different systems since that makes the engine easier to understand, reason about, modify, optimize, and rewrite.
- The physics system simulates a number of bodies, possibly connected by joints.
- The scene graph handles local-to-world transforms for a collection of nodes in a hierarchy.
- The animation system evaluates and blends animation curves for bones.
- We can calculate the velocities directly by differentiating the animation curves.
- We can record a node's transform at two different time steps and compute the velocity from the difference.
- We could add an array of Matrix4x4:s to our scene graph's last_world where we store the last world transform of every object. So whenever we want to go to ragdoll we always have a last_world transform to calculate velocities from.
- We could simulate the character backwards in time when we want to go to ragdoll and obtain a last_world transform that way.
- We could delay the transition to ragdoll one frame, so that we have enough time to gather two world transforms for computing the velocity.
[This piece was reprinted from #AltDevBlogADay, a shared blog initiative started by @mike_acton devoted to giving game developers of all disciplines a place to motivate each other to write regularly about their personal game development passions.]
Vector3 p0 = translation(tm_0); Vector3 p1 = translation(tm_1); Vector3 velocity = (p1 - p0) / dt Quaternion q0 = rotation(tm_0); Quaternion q1 = rotation(tm_1); Quaternion q = q1 * inverse(q0); AxisAngle aa = q.decompose(); Vector3 angular_velocity = aa.axis * aa.angle / dt;