Jondolf / avian

ECS-driven 2D and 3D physics engine for the Bevy game engine.
https://crates.io/crates/avian3d
Apache License 2.0
1.55k stars 120 forks source link

per freedom (rotation/transform on each axis) compliance values #198

Open mattdm opened 1 year ago

mattdm commented 1 year ago

Imagine a box with a hinged lid. The hinge is a Revolute joint, allowing rotational freedom on one axis. (Let's say X.) The limits in the Z and Y directions are effectively hard constraints (you can't twist the lid that way), as are the degrees of translation -- it doesn't slide. When you close the lid, collision with the box itself effectively enforces a limit. When you open the lid, with most hinges, it can't go all the way back and around. But that limit is usually kind of "springy". It's a soft limit.

The same kind of thing applies to other joints too, with applications both simulating real-world objects and game things which aren't exactly realistic but act as expected. (For example, a rotating barrier might be pushed past its limit with a soft compliance, but shouldn't be tipped over or moved by the same amount of force.)

Right now, xpbd uses the same limit for everything.

The first and most simple low-hanging fruit is separating compliance into angle_limit_compliance or free_axis_compliance (naming is obvious, I think) and restricted_compliance (name is less obvious; maybe just leave as compliance?).

A more advanced approach would allow for setting limits and compliance separately on all six degrees of freedom, no matter the joint type. That would allow you to easily model, say, rattling the hinge back and forth along the axis of its pin (the same one as the rotational freedom). But, maybe this is best left to creating a custom joint? Or, perhaps there could be a pre-made "Universal" or "FreeMotion" joint, which would do nothing "out of the box" but could be configured with limits on each freedom.

It would also be nice to have both hard and soft limits for joints. This probably isn't exactly like the real world, but seems easy for games. I'm thinking of a DistanceLimit, for example -- one might want to make it so once you get to some point, the imaginary rope will still stretch, but with some resistance, and then a hard limit where it will go no further.

mattdm commented 1 year ago

More on DistanceJoints on this...

Right now, as I understand it, Compliance acts as a value for all of these things:

  1. How "stretchy" the connector is
  2. How rope-like vs. stick-like it is -- can you push with it?
  3. How springy it is at returning to the "rest length" (this should probably be "rest distance", shouldn't it?)

I can think of a lot of cases where I'd want these to all be different!

Jondolf commented 1 year ago

Compliance is just the inverse of stiffness, and stiffness isn't a variable property in the sense that it would behave differently when pushing things vs. returning to the rest length.

If you had a spring, it would just be a harmonic oscillator following the formula F = -kx, where k is the stiffness constant. This is essentially what a DistanceJoint is: it just always tries to return to the rest length (displacement x == 0), and the compliance/stiffness determines the spring force.

mattdm commented 1 year ago

Compliance is just the inverse of stiffness, and stiffness isn't a variable property in the sense that it would behave differently when pushing things vs. returning to the rest length.

Yes. I'm not thinking in terms of the model, though, but rather things I want to model with it. :)

mattdm commented 1 year ago

You know how the RevoluteJoint doesn't have a "rest point" it pulls back to? It just enforces the angle limits. Ironically, while I wanted that for that joint, for DistanceJoint as a "leash", I want that to just enforce the limits. I'll go look at the code to see what I can figure out here. :)

mattdm commented 1 year ago

Having poked at this a bit more, I think DistanceJoint should drop the "rest limit" and just have the DistanceLimits. If you want the joint to return to one distance, have those both the same. That way, it behaves like RevoluteJoint does now. This solves the "act like a rope not a stick" problem.

Then, I think adding motors will address some of the other issues.

But I still think that it would be useful to separate "compliance on the limits on an otherwise free axis or translation" from "compliance on the normally-fixed degrees of the joint".

Jondolf commented 1 year ago

Yep, I agree. The rest length can be replaced by the distance limits, and for all joint types, the limit compliance should also be separate from the "fixed dof" compliance (except with a distance joint, there are no fixed dofs apart from the distance limits)