Closed alektron closed 1 year ago
Hi @alektron , Thanks for filing this issue and providing a reproduction snippet, and sorry for the very long response time.
I tried to run your snippet with the newest version of PhysX (https://github.com/NVIDIA-Omniverse/PhysX) and could not reproduce it anymore. A (potentially) related ticket was filed there (https://github.com/NVIDIA-Omniverse/PhysX/issues/153), however undoing that fix still does not cause the behavior you describe. Could you please double-check whether the problem still occurs for you?
Note that for your snippet to run with PhysX 5, all I had to change was to replace PxCreateBasePhysics
with PxCreatePhysics
.
While I did not try to reproduce the issue with PhysX 5, I can give some insight in what seemed to cause the issue and what fixed it for us. The main culprit seemed to be the order in which the solver (and therefore the contact modification callback) was receiving the shapes in the shapes pair.
With the shape pair being:
shape[0] = dynamic actor
shape[1] = conveyor
everything works as expected. But with the shape pair being:
shape[0] = conveyor
shape[1] = dynamic actor
the dynamic actor was going in the opposite direction. The insertion order of the shapes/actors seemed to influence the order in the shape pair and in some scenarios lead to the second case. Our 'fix' was to just double check which of the shapes is the one that represents the 'conveyor' and flip the target velocity if necessary.
After some debugging sessions I did have some more insight into what exactly was causing that behavior but unfortunately I can not recall most of it. The only hint I have is this comment I left in our code. It may not even be correct but maybe it will be helpful to someone:
//The physx solver will evaluate velocities relative as seen from the shape at index 1 (pair.shape[1]).
//Since the target velocity is set on a per-contact basis (and not on a per-shape basis) and there is no guarantee in what order
//the solver will get the shapes, we must account for that and flip the target velocity if the shape with surface velocity is shape 0.
To the best of my knowledge there are no guarantees about the order of pairs that come into the onContactModify
callback. So you indeed need to check which body is the conveyor and apply the target velocity accordingly.
I just always assumed that the target velocity must be in global space. As far as I know the documentation doesn't explicitly mention it so it seemed to be the most obvious assumption.
Maybe this is something that could/should be added to the docs. In my case global space was working just fine for quite a while (and especially during testing) until the bug happened seemingly at random in production. It was quite an effort to reproduce locally and track down. This could prevent some headaches for other people in the future.
I will add this to the documentation. Thanks again for raising awareness and tracking down the problem you were seeing :)
When trying to simulate a conveyor belt by using the contact modification callback and PxContactsSet::setTargetVelocity, under very specific circumstances it is possible that a dynamic actor that sits on top of the 'conveyor' moves in the opposite direction, specified in setTargetVelocity.
A standalone code snippet is added below. I tried to make it as comprehensible as possible, yet it is still rather large. The example sets up contact modification for a kinematic actor (our 'conveyor') with a constant target velocity in the positive x direction. We then perform the following steps before the simulation runs:
Some details are important to reliably reproduce the bug:
PhysX build settings: vc16win64.xml | build static lib | use dynamic WINCRT lib | Precise math: false PhysX 4.1 Commit: c3d5537bdebd6f5cd82fcaf87474b838fe6fd5fa Visual Studio 2019 v142 C++ 14
The code snippet below has no dependencies other than PhysX. PVD must be running.
My knowledge of physics engines is VERY limited. However I have been trying for a while to debug the PhysX SDK to find the issue. I obviously could not fix the issue but there are some things I have noticed. I will add them here, in case it might help.
solveContactBlock
gets chosen from gVTableSolveBlock but ONLY in the reproduction case. When e.g. using a multi shape actor for actor A AND B, other solver functions get used.solveContactBlock
then callssolveContact
where the 'flipping' of the velocity sign seems to take place. Specifically when linVel1 gets calculated. deltaF is a positive value, which (at least intuitively) makes sense. However the result of the calculationcauses linVel1 to become negative which seems to produce the negative velocity (?)