NVIDIAGameWorks/PhysX

Handling one body with multiple collisions in a single step?

tbasch opened this issue · 7 comments

Hi, I'm trying to use PhysX mostly for collision detection and want to craft my own collision responses. I have a few questions:

  1. What's the best way to achieve this with respect to the simulate() / advance() / collide() functions?
  2. In the scenario where one object collides with two others at the same time, in what order are the collisions reported, and are they reported all at once or do we get to handle each collision as they are detected? Image you have a sphere rolling towards the corner of a room? If it manages to collide with both walls A and B at the same time, can we handle the collision with A and modify the sphere's physics state such that it doesn't actually collide with B?
  3. I'm running into issues calling setLinearVelocity from an implementation of PxSimulationEventCallback::onContact. This is in attempt to handle each collision as it happens to get precise control, but PhysX reports a race condition. The scene is created such that an RW lock is not required. Is there any way to address this, or am I just doing this wrong?

Thanks in advance!

Collision detection in PhysX will report both collisions at the same time provided the shapes are within the contact distance. The contacts report the contact point, normal and separation value (-ve values mean the shapes are penetrated).

If you would like to write your own collision response, you have a couple of options. One would be as you are attempting to do, but what you would probably need to do is store out the contacts, then run your collision response after fetchResults() completes. The error you are getting relates to you trying to modify the state of an actor during callbacks in fetchResults, which is not legal.

The alternative approach you could take would be to use immediate mode. Immediate mode is a different API to get at PhysX's internal collision and solving code, which exposes it via a set of C functions that you can assemble together to implement the simulation. It is often used for embedded small simulations, e.g. secondary physics on an animated character, where being able to embed the simulation of a few small rigid bodies into the update loop is beneficial from the perspective of both performance and simplicity because animation doesn't have to be broken up into stages that run before and after the physics scene is run.

If you took the approach of using immediate mode, you should be able to replace the PhysX solver with your own implementation.

Thanks for the quick reply! I understand things a little better now.

In the solution where contacts are queued, let's say in one 16ms frame, an object O collides with objects A and B at the same time, both at 8ms into the frame (again, like the sphere rolling towards the corner of a room). If I were able to handle the response for collision with A, it's possible that I might modify the trajectory such that it would not then collide with B. In such a case, I would prefer to be able to set a new velocity for O and then let PhysX simulate the remaining 8 ms of the frame (or until O collides with something else, which I would then handle, whichever comes first).

In other words, I'm fine with PhysX doing the integration, I am just looking for precise control over how things bounce.

  1. Is it possible to just set a new velocity mid-simulation and let PhysX simulate from there? Or would I need to manually step the simulation by some amount, like 1ms, and call simulate over and over and handle collisions between each step?
  2. Can this be done with PCM, or do I need to enable CCD? Regardless of tunneling, it sounds like I would need to enable CCD to be able to do this.

Thanks again for your help! It is greatly appreciated!

Actually, this might be a clearer example:

With regular, uninterrupted simulation, in one simulation step of, say, 16ms, object O collides with object A at 7ms, PhysX calculates the response, and continues simulating the frame. In that same frame, at 9ms, O collides with object B.

Is there a way I can calculate my own collision response at 7ms where I can send object O on a different trajectory such that the collision at 9ms then doesn't actually happen? I guess what I'm trying to ask is if there's a straightforward way to implementing my own solver that can modify trajectories while the frame is still being simulated.

With PhysX, when you take a simulation step, collision detection is run once at the beginning of the step. This factors in the shape's contact offsets and produces a set of contacts with distance information - a positive value means the shape is separated, while a negative value means the shapes are penetrated. The goal of the solver is to reach a state of zero penetration. The separation values therefore become a bias term added to the velocity projection of the constraints such that collisions with distant objects only initiate a response if velocity*dt exceeds separation. Similarly, small penetrations produce additional forces to correct the positional errors.

PhysX additionally has some options for CCD. These take the form of speculative CCD (adaptive contact offsets) and an additional CCD post-process that sweeps fast-moving geometries through the scene to re-trace their steps to determine if any collisions were missed. The speculative approach doesn't involve additional collision detection, although it can result in generating significantly more contacts, whereas the latter involves additional collision detection after the discrete simulation and solver have completed.

If the collision at 7ms and 9ms both occur at low speeds and are detected by the discrete simulation, there is no way to ensure the collision doesn't get reported, but it is quite likely that the latter collision will not apply a response, although you may need to give the solver an increased number of iterations to guarantee this, as the solver doesn't consider the time-ordered sequence of collisions but it should eventually correct any forces applied by the later constraint after the response to the first contact adjusts the velocity such that the second constraints' contact could not have occurred.

If the collision at 7ms and 9ms occur at high speeds and were not detected by discrete simulation, but instead by the CCD system, then these collisions would be processed in the order they were detected and the collision at time 9ms would not occur at all.

Unfortunately, a lot of this happens transparently when you call simulate()/fetchResults(). As mentioned, you could use immediate mode to give yourself complete control to be able to substitute any part of the pipeline with your own implementation. Immediate mode doesn't have official CCD support, but you can implement CCD using sweeps and distance queries, which are both supported by the scene query API, so you could build your own simulator to achieve this.

However, I have to ask what it is that your end goal is. If it's just experimental/educations/fun to make some small scale simulations, then I'd recommend you look at immediate mode as a great way to make a very simple rigid body simulation with really easy flexibility to copy out chunks of code into your codebase and modify them to do what you want. If the goal is to build something that's dramatically better than what PhysX is already capable of, it would be great if you could explain what the deficiencies are that you're trying to address because we may already have solutions you could use to avoid having to try and reinvent the wheel.

Thank you for the thorough reply! I poked around some immediate mode stuff and I will go down this route to see how far I can go.

The end goal is to implement a form of arcade-style physics where collision detection is thorough and accurate, but the responses are largely clamped to certain values depending on input. This sacrifices a bit of realism in favor of path predictability and player control. PhysX is really high quality, both in detection and response, and I would like to be able to use as much of its collision detection as possible while being able to (hopefully easily) write my own solver.

Hence the example of O colliding with A, bouncing in a physically accurate way to then collide with B. Whereas in my solver, it won't bounce in a physically accurate way and therefore is not guaranteed to collide with B, even in the same frame.

I see an immediate mode example, so I'm going through that and will see where this goes. Thanks again, and I'll keep you posted!

Related to this, would CCD contact modification work, or is it still not valid to modify body velocities?

Not easily, although if you were willing to ignore any warnings in debug/checked builds and you were willing to jump through some hoops, you might be able to get it to work. In those callbacks, you don't have low-level access so the internal velocity buffers being updated by the simulation. The velocities/poses you receive when you query the velocity/pose of an actor via PxRigidBody will be the body's initial velocity at the beginning of the frame, which could be quite different from velocity that is internally being worked on. The externally-accessible velocities/poses get updated during fetchResults.

You can request pre-solver velocities reported alongside the pair, which will give you a snapshot of the internal values, but those values won't change if you call setLinearVelocity/setAngularVelocity/addForce etc. on the body because your changes would be buffered and applied at the end of the frame in fetchResults, effectively overwriting the state produced by the solver.

I don't think you could make this work via existing callbacks. With contact mod, you can change the properties of the contacts but you can't apply your own constraint forces.

However, you do have full source code for the simulation, so if you are confident enough, you could add additional functionality to support what you want to do, but it's not something that's currently supported. You could potentially extend the functionality in the existing callbacks or add an entirely new set of callbacks that do what you want.

Immediate mode is more flexible because it's basically a set of building blocks that you can put together in whatever way you want and replace the parts that don't match your requirements. It's more low-level and you would have to fill in some blanks to do what you want, but you might feel less like you are trying to jam a square peg into a round hole than you would trying to get the full fat PxScene-based PhysX simulation to do what you want.

FWIW, it is also totally possible to implement your own entire solver inside PhysX retained mode (PxScene-based simulation). If you take a look at Sc::Scene constructor, you should see that we use conditional checks to select between 4 different solvers (2 GPU-based, 2 CPU based). The rest of the simulator interacts with the different solvers through a common interface. You could conceptually implement your own solver via this interface. It would not be an easy task because the inputs to these are internal types rather than well-documented external types, so you would have to be good at inferring meaning from other people's code. You could start by copying/pasting one of the existing CPU solvers into your own code, hook it up and then gradually modify it to make it do what you want.