PhysX 3 Character Controllers: capsule climbing over another (step-offset, radius & height)

EDIT: Hopefully it will be clearer with a little drawing:

As you can see, it seems that – with PhysX 3 – as soon as capsule B’s radius is greater than capsule A’s radius+height, B climbs over A (maybe because of the round smooth shape of B’s bottom half-sphere?), even though B’s stepOffset is much smaller. PhysX 2 didn’t do that.


It seems that the behavior of capsule auto-stepping for controllers hitting each other has changed from PhysX 2 (NxCapsuleController) to PhysX 3 (PxCapsuleController)?

I have 2 capsule controllers, with the following parameters same for both:

  • slopeLimit : 35° (correctly stored as cosine, i.e. 0.819)
  • stepOffset : 0.50 m
  • climbingMode : eCONSTRAINED (precisely PxCapsuleClimbingMode::eCONSTRAINED)

Now the capsule A has:

  • height : 2.00 m
  • radius : 1.00 m
    (for a total height of 2.00 + 2*1.00 = 4.00 m)

and capsule B has:

  • height : 1.00 m
  • radius : 2.00 m

If I move B onto A (by successive calls to move() with a displacement vector towards A), the behavior is the same with both PhysX 2.8.3 and 3.2.4: B is “blocked” by A and slides horizontally around it (against the sides).

But now if I increase B’s radius to e.g. 3.00 m (or more),
then with PhysX 2, B is still blocked by A, but with PhysX 3, B rides over A! as if the radius were added to the stepOffset for auto-stepping?

How to fix that?

Thank you very much…

Actually I have the same problem with character-controller-capsule vs static-box collision, as shown in the following image:

Does anybody else have the same problem?

Thank you.


I didnt have this problem I think. ( Okay, I use a PxBoxController )
So - maybe your parameters are wrong.

Try to modify your step offset.
Whats your PhysX Scene scale?
Whats your contact offset?
Which kind of calculation do you use for your delta time - for the PhysX simulation time?

Maybe you need to code your own behaviorCallback - look into the PxCapsuleControllerDesc.

But maybe there is a bug inside the PxController -
look at the curved surface of the capsule. In your sketch, the new capsule high is almost
higher than the obstacle. When you add the step offset you are higher than it and the PxController
can climb it, even when you said that this shouldnt be possible.

Of course, you could try to use invisible walls - but I guess you dont want to use them.

Hi ScreenOfDeath, thank you for your response. I will try to answer your points.

=> Yes, I can’t use a box controller because I need some “smooth horizontal sliding” between characters. Too bad there isn’t a “PxCylinderController”, that would hopefully have solved the problem…

=> I did. For now it is 0.50 m but I tried things like 0.10 m, 0.01 m and even 0.001 m (i.e. 1 mm).

=> The default PxTolerancesScale() (i.e. length(1), mass(1000), speed(10)).

=> 0.0001 m (i.e. 0.1 mm). I tried tweaking it (multiplying it by 10 up to 1.00 m) with no results.

=> I took the substepper from the Crab sample. PxScene::simulate() is always called with a fixed dt of 1/60 s. (The game’s main loop itself is more around 1/30 s.)

=> I have already tried that (since my original post). Returning either eCCT_CAN_RIDE_ON_OBJECT, eCCT_SLIDE, 0, or even the new eCCT_USER_DEFINED_RIDE (I switched temporarily from PhysX 3.2.1 to 3.2.2, and even 3.2.4, just to test) didn’t solve the problem (well, with eCCT_SLIDE the capsule slided down after climbing over the other instead of staying still, but that’s not the issue).

=> I don’t quite understand that part… By “capsule high” do you mean its height (the height of the cylinder part), its “full height” (height + 2*radius), or something else? And more important, why should I “add the step offset”? because I would say that’s precisely the problem:

it seems that

  • however small the capsule’s slopeLimit [say 1°],
  • however small the capsule’s stepOffset [say 0.01 m]
  • and however small the capsule’s height [say 0.01 m (yes that capsule is almost a sphere)],
    as soon as the capsule’s radius [say 1.05 m] is greater than the obstacle height (box’s height or other capsule’s radius+height, it seems) [say 1.00 m], then the capsule can step over it, seemingly ignoring any other limits (only because of the “curved surface” shape of it’s bottom half-sphere? but why in PhysX 3 and not in PhysX 2 then?)…

=> Sadly you guessed right; actually I couldn’t use them even if I wanted to, because I don’t own the code, I’m just porting an existing base from 2.8 to 3.2 and must keep as close as possible to the old behavior with minimal added run-time overhead…


hm. Sorry for this short answer - I will write a longer version of it tomorrow.
Maybe you should use obstacles instead of invisble walls - the PhysXGuide said that this
is the recommended way to solve issues like this.

The obstacles are not a new SDK object - its only “visible” and collidable with a PxController.
The exist only a few frames when they are needed.
Look into the PhysXGuide and read it. Maybe its a solution for your problem.

Of course, you could look into the PxController source code, and try to fix it :)

Have you tried returning eSLIDE?

class MyControllerBehaviorCallback : public PxControllerBehaviorCallback

        virtual PxU32 getBehaviorFlags(const PxShape& shape)
                    return PxControllerBehaviorFlag::eCCT_SLIDE;
              return 0;

        virtual PxU32 getBehaviorFlags(const PxController& controller)
              return 0;

        virtual PxU32 getBehaviorFlags(const PxObstacle& obstacle)
              return 0;

        virtual ~MyControllerBehaviorCallback(){}

  class MyUserControllerHitReport : public PxUserControllerHitReport

  virtual void onShapeHit(const PxControllerShapeHit& hit)         {}
  virtual void onControllerHit(const PxControllersHit& hit)        {}
  virtual void onObstacleHit(const PxControllerObstacleHit& hit)   {}
  virtual ~MyUserControllerHitReport(){}


Then use them in the descriptors:

  cDesc.callback          = &gUserControllerHitReport;
  cDesc.behaviorCallback  = &gControllerBehaviorCallback;

@HaiLocLu Yes:

But thanks for suggesting. (BTW I’m not working on the PhysX code anymore, another dev got the hot potato :p)