NVIDIAGameWorks / PhysX

NVIDIA PhysX SDK
Other
3.16k stars 802 forks source link

How to use Mass Scaling #583

Open alanjfs opened 2 years ago

alanjfs commented 2 years ago

Hi NVIDIA,

In the documentation for PhysX 4, under the Joints section, it reads:

...if you have two objects in a ragdoll of masses 1 and 10, PhysX will typically resolve the joint by changing the velocity of the lighter body much more than the heavier one. You can apply a mass scale of 10 to the first body to make PhysX change the velocity of both bodies by an equal amount. - Reference

I'm searching high and low for this "mass scaling" feature but am coming up empty. What should I be looking for? Does this only apply to custom joints, or does it also apply to e.g. the PxD6Joint?

The closest thing I got was a PxConstraintInvMassScale as an argument of the D6JointSolverPrep in ExtD6Joint.cpp, but it's not clear whether this is what the documentation is referring to or how to manipulate this argument.

The next-closest thing is a contact modification callback, in SnippetContactModification.cpp except that doesn't seem related to joints.

Any thoughts?

kstorey-nvidia commented 2 years ago

Hi

This can be controlled by PxConstraintInvMassScale. The mass and inertia scales can be uniformly scaled independently, so this structure has 4 floating point values corresponding to the invMass and invInertia scales of the first and second body respectively.

As these are inverse values, this means that a value < 1 makes the body's mass appear larger for the constraint and a value > 1 makes the body's mass appear smaller. You can make the constraint act completely one-sided by setting the invMassScale and invInertiaScale on the body you want to be unaffected by the constraint to 0.

Therefore, if body A has a mass of 1 and body B has a mass of 10, you can result in the constraint behaving as if their masses were equal if you either set the invMassScale of body A to be 0.1 or the invMassScale of body B to be 10. The applied forces reported by the joints will be different in this case because the first option involves effectively simulating the constraint between a pair of bodies with masses of 10 and the second option involves simulating the constraint between a pair of bodies of mass 1. If you use a hard constraint, the behavior will be the same either way - just the reported forces will change. If you use soft constraints (e.g. drives or limits with spring values), the behavior of simulating a pair of bodies each with mass 1 or each with mass 10 will potentially be different because the spring will be acting on a different load.

Hope this helps

Kier

alanjfs commented 2 years ago

Thanks for getting back, but I still don't understand.

PxD6Joint* pxjoint = ...
pxjoint->PxConstraintInvMassScale(1, 1, 1, 1);
// error C2039: 'PxConstraintInvMassScale': is not a member of 'physx::PxD6Joint'

Where do I use PxConstraintInvMassScale? What function or class takes this struct? The documentation provides no clue.

kstorey-nvidia commented 2 years ago

PxJoint::setInvMassScale0, setInvMassScale1, setInvInertiaScale0, setInvInertiaScale1

alanjfs commented 2 years ago

Ah! Thank you! ❤️