Long time no update.
I decided to take a break from the physics, and to go back to trying to achieve Character Physics Happy Fun Time™ by other means.
I made a PlacedFootConstraint
which constrains a point on a foot in place relative to another object, and optionally locks the orientation as well. The idea here is that it's much more reliable than the collision-detection + dynamics approach, which was always jittering, or allowing the foot to sink into the ground, or some other stupid thing like that. The exact setup for creating and breaking PlacedFootConstraint
instances is still subject to change, but the basic idea is that when a Dood
steps, a collision detection callback for the foot will execute, and if my code decides it likes it it will create a PlacedFootConstraint
based on the ContactPoint
data. Then when the Dood
wants to lift that foot off the ground, it will destroy that constraint. Also in theory it will be possible for the constraint to "break" from the physics side, e.g. if the Dood
gets hit really hard and goes flying.
I've made a few tweaks to my "cheaty character physics system" since the last time I mentioned it here. Previously, it conserved linear momentum but not angular. Now it conserves both. Here's the gist of the algorithm:
Compute initial net linear and angular velocity of the Dood Dood::DoCheatyPose
directly modifies the linear/angular velocity of each bone
Compute change in net linear and angular velocity, aka "cheaty velocity" Dood::MaybeSinkCheatyVelocity
has the option to modify the "cheaty velocity", e.g. in order to sink some of it into the ground via the PFCs
Uniformly distribute the undoing of the remaining cheaty velocity
I believe this should be a good framework to build off of. I expect it will be easier to implement something that works in these terms than something that works in terms of per-joint torques, like I was trying to do before. I think the tiny amount of physical cheaty-ness is worth it.
My original approach (from earlier versions of the cheaty physics system) was to specify an orientation for each joint (and the root bone of the skeleton), and then set the linear and angular velocities of each bone to whatever they need to be to get them into position by the next tick. This technique produces the best out-of-the-box results: if I tell it to do the rest pose, and the PFCs are positioned properly for that, the Dood
stands there very nicely... not quite rigid, but it gets the rigid bodies into a state that very nearly matches the pose I gave it.
But my goal is to make it stand and walk on varied terrain. It needs to be able to satisfy any configuration of the feet (within reason), not just the rest pose. And I don't know how to implement that.
One big problem with a per-joint orientation approach is that if there are multiple PFCs, not every configuration of joint orientations is going to be valid (let alone "good"). That is, if I start with one PFC's constrained pos/ori and move through the chain of joints to get to a second PFC, rotating and translating my pos/ori according to each joint, the pos/ori I end up with isn't necessarily going to match the constrained pos/ori of the second PFC.
About a year ago (well before I came up with the cheaty physics system) I experimented with a minimization-based approach to IK, where I told it the goal pos/ori of a foot relative to the pelvis, and it would figure out how to do it. But it was expensive and I had to spread the work over multiple simulation steps. That was good enough when I was telling a foot where to step, but I don't think it will work when there are multiple constraints on the skeleton: I don't think I can rely on this sort of "WIP over multiple simulation steps" solution to be a valid configuration.
Most recently I tried an approach where I just picked a pos/ori for the pelvis bone, and then the knee joint's position is constrained to a circle... and I would then select a point on that circle, and orientations for the two leg bones. But it hasn't been working, and I have no ****ing clue why. I've been reduced to shotgun-programming
There are a few things I've figured while messing with this approach, though. One, I noticed that my Mat4::FromPositionAndOrientation
method transposes the 3x3 rotation matrix portion of the Mat4
, while Mat4::FromQuaternion
does not. Sorting that one out is going to be a doozy, as Mat4::FromPositionAndOrientation
is used all over the place, and I'm pretty sure Mat4::FromQuaternion
is too. Second, I've noticed that if I try to tell the per-joint-orientation cheaty physics thing to do an orientation that exceeds a particular joint's rotation limits, bad stuff happens.
I also tried a more forward-dynamics-ish approach where I only modified the velocity data of select bones within the Dood
. Specifically, I told the bones of the spinal column to orient to face the "yaw" direction, I told the pelvis to move up, and I told the feet to stay in their PFC-constrained pos/ori. At first this looked like it was going to turn out nicely... but it didn't. It only worked if I kept all the "cheaty velocity" (i.e. MaybeSinkCheatyVelocity
changes the linear and angular "cheaty velocity" to zero, so nothing is undone). And anyway it looked much worse "out-of-the-box" than the per-joint orientation scheme.
So uh... I don't know what to do. I'm leaning toward something that uses the per-joint orientation scheme, though.