Sign in to follow this  
  • entries
    2
  • comments
    2
  • views
    8494

Handling a rigid actor carried by the player in PhysX

Sign in to follow this  

2483 views

This took me a bunch of time for a number of reasons - I'm still very new to PhysX, there were a number of issues that sidetracked me and coming up with a reproducible test scenario is actually a lot harder than it may seem at first glance. The number one problem that I faced, however, was a lack of information, which, combined with a couple of rash misreadings of the PhysX API, resulted in a lot of time lost for naught.

I tried a number of approaches, but I think I finally have it sorted out the way I want using a semi-kinematic solution suggested here. I'm posting some notes in case someone finds them useful:

  • use [font='courier new']setLinearVelocity()/addForce()[/font] and [font='courier new']setAngularVelocity()/addTorque()[/font] with [font='courier new']PxForceMode::eVELOCITY_CHANGE [/font]to keep the actor in front of the player, facing away from them
  • be sure to set the angular/linear velocity to zero after each substep, since the solver can introduce unwanted movement, which needs to be specifically killed
  • getting rid of jitter is primarily a matter of enabling CCD and substepping. I ended up settling on 3 substeps.
  • leave max angular velocity at default, but disable damping on the carried object using [font='courier new']setAngularDamping(0)[/font]
  • [font=arial]disable gravity for the carried actor[/font]
  • the most important thing is to disable automatic rotation for the actor using [font='courier new']setMassSpaceInertiaTensor(PxVec3(0, 0, 0))[/font]. Annoyingly the name and documentation make this function sound a lot more fancy than it really is. In this particular case it's a substitute for disabling automatic rotation around specific axes. This functionality was apparently present under a very different guise in previous versions of PhysX
  • for the carried actor to be blocked by other dynamic actors, set its mass to something very small, as PhysX treats zero mass as infinite, effectively otherwise turning the dynamic body into a kind of kinematic actor, which pushes all other dynamic bodies out of its way. In particular, I'm calling [font='courier new']PxRigidBodyExt::setMassAndUpdateInertia(dynBody, PxReal(0.0001))[/font] when the object is picked up and restoring its mass when it is dropped. Glossing over this the first time I read the documentation on actor mass cost me dearly.
  • even with this in place, I'm still seeing jitter when doing some extreme forcing of the object. Eg, when the player stands next to a wall holding a box and turns into it, the box will start jittering as it is left behind the player's back (since the box is always facing away from the player, it needs to perform a considerable move and almost half a rotation (or depending on the direction in which the player is turning, more than half a rotation) within whatever number of substeps you are using). My solution is to drop the item when it goes behind the player's right axis. I suppose increasing the number of substeps might help, but even though I have almost no physics to speak of, the performance impact is not that trivial (that being said, I am in debug mode with PvD enabled using the full profile)
  • I am seeing no jitter or penetration when angular velocity is zero. Hence, when trying out different things, I considered switching the box's cuboid shape for a capsule, which doesn't need to be rotated. This might be a good option for a variety of reasons, the most notable of which is more natural sliding introduced by the capsule's round shape
  • I'm calculating the required angular velocity using atan2. Note that pushing the carried object still yields jitter, in particular when crossing over atan's -PI/+PI wraparound, so a special case fix is necessary:
    PxReal rotTar = math::atan2(vecTarget.z, vecTarget.x);PxReal rotCur = math::atan2(vecForward.z, vecForward.x);if(Sign(rotCur) != Sign(rotTar)){#define TAN_QUADRANT(x) (x < -math::Const::HalfPi) ? 1 : ((x > math::Const::HalfPi) ? 4 : ((x < 0) ? 2 : 3)) int32 quadrantRotCur = TAN_QUADRANT(rotCur); int32 quadrantRotTar = TAN_QUADRANT(rotTar); if(quadrantRotTar != quadrantRotCur) { if(quadrantRotCur == 1 && quadrantRotTar == 4) { rotCur += math::Const::TwoPi; } else if(quadrantRotCur == 4 && quadrantRotTar == 1) { rotTar += math::Const::TwoPi; } }}rotDelta = rotCur - rotTar;

    • as of right now the actor's collision with the CCT (character controller) is still wonky. It collides when the player walks into the actor, but seems to be ignored when the box needs to travel to the other side of the player. Ironically, while essentially downright broken, this behavior is very much desired in 3rd person mode, since the player can cause the CCT to flip by simply moving the mouse across its origin
Sign in to follow this  


2 Comments


Recommended Comments

Yes, I got it working, but it took a lot of tweaking. The bottom line is that it simply cost me a whole lot of time to get right as there are a lot of things you need to figure out and get correct right off the bat.

 

The above piece of code is only there to hilight the tan periodic wraparound, which causes the carried object to jerk when crossing it. The entire thing is considerably longer, but won't be that difficult to write if you acquaint yourself with the PhysX API a bit.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now