I'm implementing object carrying. As my game is from a top-down 3rd person perspective, this needs extra care as I cannot cheat in screen space or use some other fakery to achieve the illusion of carrying and colliding an object in the player's hands.
After going through a joint-based and a kinematic test solution, I've managed to tweak a semi-kinematic approach to the point where it almost looks okay. Essentially I'm doing what the guy here suggests: keeping the carried object as a regular non-kinematic dynamic actor and setting its linear (and optionally angular) velocity to match the necessary displacement so the object would end up in front of the player every time the character controller moves and/or turns.
Note that a joint-based solution does not work, because while keeping the carried object relative to the player isn't that hard, having the it face int the same direction as the player requires a call to setGlobalPose(), which bypasses collision detection and causes the carried actor to clip into geometry.
Similarly, turning the carried object into a kinematic body and using setKinematicTarget() doesn't work, because kinematic bodies in PhysX implicitly have infinite mass and push all dynamic actors out of the way. Also, they do not collide with static geometry. By design. Which is basically saying that kinematics weren't meant to be used like this (although I suppose one could use some far too complicated contact point modification voodoo to fake it).
This leaves the third solution, which requires some tweaking to properly align the carried object in front of the character controller (which itself is kinematic), but otherwise has the most potential so far.
(TL;DR - questions be here) Nevertheless, there are three issues with it:
1) collision with static geometry causes the carried actor to jump erratically as it's pressed against a wall. This forces it to wobble badly and clip into geometry and/or slide up until the actor ends up on top of the static blocker (I really can't tell why, but both seem to happen, sometimes during the same run). The behavior I want is far less intrusive: essentially I want the carried object to just stop if blocked and I want to run my own test that will determine if it's too far off the player's orientation vector and needs to be dropped (essentially simulating joint breakage).
2) I do not want the carried object to affect dynamic objects. I've tried setting its mass to zero, but it still pushes everything out of its way. Dynamic objects normally block the CCT (character controller) as if they were fixed geometry, but for some reason a dynamic actor with mass zero and velocity set via setLinearVelocity() still affects them (and is affected by them).
3) the third problem is the most nuanced and may well be borne out by my poor knowledge of the API. Essentially it has to do with when PxCharacterController::move() should be called. Notably, for the sake of consistency, I need to use the actual distance between positions measured before and after PxCharacterController::move() to move the carried object. However, as far as I can tell, PxCharacterController::move() is not executed as part of the simulations step (eg it's not deferred the way setKinematicTarget() calls are), but rather acts like a separate write call to PxScene, which is run independently. That being said, calling PxCharacterController::move() before a simulation step for a given tick will yield a proper offset, but will either potentially collide the CCT with the carried object, thus slowing it down, or if I disable collision for the object for the duration of the move() call, potentially clip the CCT into the carried object in case it is blocked by a solid on the other side. Calling move() after the simulation step makes more sense, but can have the carried object jitter as it tries to move to a projected position (and then snaps back during the next update) in case the CCT is blocked.
Truth be told, I'm not overly concerned about the last point for the time being. I am, however, not really sure what to do about points 1 and 2, which are both game-breaking. I've tried quite a few things and I'm running out of ideas... Any thoughts?
* note: while I think all of the above points are a matter of working out a few details, a fourth option would be to go back to a joint-based solution and use setAngularVelocity() similarly to my current solution to bypass the call to setGlobalPose(). I don't like the joint solution, though, as it's more complicated than the semi-kinematic one.