PhysX rigidbody jitters if pushed into corners (depenetration issue)

Started by
6 comments, last by Lewa 4 months, 3 weeks ago

Recently i noticed having a very strange issue if (dynamic) rigidbodies are pushed into corners/walls (like the edge of a room where two walls meet). Rigidbodies start to jitter very strongly (as if a depenetration happens but is unstable).
Here some videos for illustration. (Note that the jittering happens if i push the rigidbody with addForce() into the corners) One is a 90 degree corner, the other one is around 45 (if not less) and the third video shows how a gliding rigidbody clips through the floor. (I'm not even applying a force there during the depenetration attempt.)

  • simulation tickrate is 100 fps
  • Mass of the rigidbody is 1000
  • Dimensions of the cube are around 1.7x4.5x1.35
  • the static geometry is a triangle mesh
  • no CCD is used
  • tried to increase solver iterations with setSolverIterationCounts without any success.
  • havent touched any offsets/thresholds (as far as i know) so everything should be set to default.


It looks incredibly unstable and the fact that a gliding rigidbody can easily clip through a narrow V shaped corner like that makes me wonder if i have overlooked/misconfigured something.

2 videos where jittering appears if i push the rigidbody with addForce() towards the corner:

Here i'm not eveny applying a force. The rigidbody has a friction of 0 (or almost zero), i simply applied an impulse and let it slide towards the corner.

Any idea/hints as to what could cause this/how the stability could be improved?

Advertisement

The first two videos where you are applying a force look like the force is too strong. I see similar behavior in my physics engine if the gravity is too high. Consider what happens when you apply a large force to an object. What the physics engine is probably doing each frame is:

  1. Set object force vectors to 0
  2. Add forces from gravity and user
  3. Integrate force to get change in velocity over delta time
  4. Detect collisions (with CCD or not)
  5. Solve collisions/penetration constraints (update velocity)
  6. Integrate velocity to get the new position.

The issue occurs because the (non-CCD) collision detection uses the previous frame's position to detect collisions. This means that if the box is almost touching (but not colliding yet), that there will be no collision and thus no collision resolution. This allows the box to penetrate into the wall/floor an amount proportional to F*dt/mass. On the next frame, the collision is detected and the solver tries to correct for the penetration. It might push the object out a little too far. If that happens, then you can get the same situation on the next frame where the over-penetration occurs. This is what causes the jitter.

I don't know what controls PhysX exposes, but in my engine I would reduce jitter by adjusting the speed at which penetrations are resolved. This is usually controlled by a parameter in the range [0,1] which represents what fraction of the penetration to resolve on the current frame. A value of around 0.2 to 0.3 is typically stable, more than that can be unstable and produce jitter. Maybe PhysX exposes a similar parameter. The term for this penetration resolution approach is called “Baumgarte stabilization.” In Unity which uses PhysX there is this parameter, though it hints that the penetration resolution is linear and affects velocity, which is not a good thing for stability. The method I described earlier is exponential (correction rate decreases over time proportional to the penetration).

You can also try turning on CCD and see if that helps, though it may not help depending on the implementation (e.g. if CCD is just between swept bounding spheres). To help it would have to be full CCD which accurately determines the time of contact (conservative advancement), and this is going to be slow.

As for the last video, it's hard to say exactly what is going on there. It might be a variation of the same issue - the top obstacle pushes the box down when it collides, causing overcorrection, and then on the next frame the bottom obstacle pushes back too far. At some point the push is enough to push the box center below the floor plane, which causes the box to pass through the floor. The result is that the box only collides with either the upper or lower obstacle, but never both at the same time. This prevents the box's motion from being stopped fully as it should.

However, it still seems a little strange, as if there are a (too) limited number of contact points that are solved per object (e.g. 2 instead of at least 4, or maybe the contacts are in the wrong place). One likely possibility is that PhysX collapses the contact point pairs to a single point for solving (instead of having a separate point on object A and B), this can produce incorrect motion if the penetration is large (point on A is far from point on B), if it's using the midpoint (p_A+p_B)/2 for solving collisions. I don't know why physics engines commonly make that simplification which makes no physical sense. It works much better to use separate points and doesn't cost that much extra compute to do so. Unity uses PhysX, and they only return a single point per contact.

Another common trick is to set all masses 1 to avoid some stability issues (e.g. stacking heavy object on top of light object), but I don't think that would help here because you only have 1 dynamic object.

Yet another possibility is that you have set up the center of mass and inertia tensor of the object incorrectly. If these are not realistic, then you can get a situation where objects don't rotate realistically when perturbed by collision.

Aressera said:
The first two videos where you are applying a force look like the force is too strong

The physics object has a mass of 1000 and i'm applying a force of 8000 to it. Is that already considered to be too strong?

Aressera said:
I don't know what controls PhysX exposes, but in my engine I would reduce jitter by adjusting the speed at which penetrations are resolved. This is usually controlled by a parameter in the range [0,1] which represents what fraction of the penetration to resolve on the current frame. A value of around 0.2 to 0.3 is typically stable, more than that can be unstable and produce jitter. Maybe PhysX exposes a similar parameter. The term for this penetration resolution approach is called “Baumgarte stabilization.”

Physx has something similar. Have to try that.

I made the same test where i reduced the mass of the object to 100 and set the force to 800. You can see how the object accelerates due to the force applied. (It's not that fast. If that acceleration/force is an issue then i'm wondering how this behaviour hasn't cropped up to the same extend in other games. Especially with the 90 degree corner case.)

CCD hasn't really helped before but i'll try again.

Might have to check out unity & godot and rebuild a similar testscenario there to see if the instability is as bad as show in the videos.

It's issues like that which brought me to the Newton physics engine. It's not completely free of jitter, but still robust in cases where any other engine i've ever tried fails.

But i think it would help to make inertia more uniform. Your test object is long on one axis. What happens if you set the inertia as low as that of the other two axis?
Also make the max force / torque your picking joint can apply as small as possible.
Those tricks won't fix the problem, but maybe it becomes acceptable.
Otherwise do what Half Life did. Hide your inaccuracy and jitter by introducing a explanation for the issues. The gravity gun uses some ‘high tech force field effect’, which likely explains the jitter. So if we play the game, we wont complain too much about it, thinking it is caused by the gravity guns technological limitations.

Aressera said:
However, it still seems a little strange, as if there are a (too) limited number of contact points that are solved per object (e.g. 2 instead of at least 4, or maybe the contacts are in the wrong place). One likely possibility is that PhysX collapses the contact point pairs to a single point for solving (instead of having a separate point on object A and B), this can produce incorrect motion if the penetration is large (point on A is far from point on B), if it's using the midpoint (p_A+p_B)/2 for solving collisions. I don't know why physics engines commonly make that simplification which makes no physical sense. It works much better to use separate points and doesn't cost that much extra compute to do so. Unity uses PhysX, and they only return a single point per contact.

Interesting. When i made my own physics engine, it was a central idea to always use only one contact for a pair of bodies. It could do stacks without problems and worked well.
My weighting was considering penetration depth, and this worked well enough so the contact joints settled at the correct position.

Recently i came back to this idea, because even Newtons contacts were not accurate enough for the self balancing ragdoll i work on. It takes too many frames until Newton finds the right force magnitudes, and the ragdoll easily looses balance because the ground reaction force is slightly different than expected.
So i made a custom contact joint, and use only one per foot. Having control over the precise position of the contacts my balancing is now super robust and reliable. Big success for me.

I still i think a physics engine using only one contact could work and might be an interesting optimization. But it surely isn't as easy as i thought back then.

Did a brief test in unity to replicate the clipping through floor test from earlier:

Simply created a new scene, drag and dropped the .obj mesh in there, set up the bodies and colliders (static and dynamic) and applied a constant force of 8000 to the rigidbodies local X axis.
It jitters a bit on contact and gets to rest even while constantly having the force applied. (and more importantly, it doesn't clip through the geometry.) All this while using discrete collision checks.

I must be doing something incredibly wrong with my PhysX setup.

Lewa said:
Simply created a new scene, drag and dropped the .obj mesh in there, set up the bodies and colliders (static and dynamic) and applied a constant force of 8000 to the rigidbodies local X axis.

But in your videos you seemingly use a picking joint driven by mouse input. That's a different situation than applying a constant force. What happens if you do such constant force setup in your engine?

JoeJ said:

Lewa said:
Simply created a new scene, drag and dropped the .obj mesh in there, set up the bodies and colliders (static and dynamic) and applied a constant force of 8000 to the rigidbodies local X axis.

But in your videos you seemingly use a picking joint driven by mouse input. That's a different situation than applying a constant force. What happens if you do such constant force setup in your engine?

The camera is moved by the mouse/gamepad. The force however is applied alongside the forward axis of the rigidbody.

I seem to also have found the problem. I was wondering if i'm by any chance modifying the contacts of the physics simulation.

Turns out i did but not intentionally. I had debug code left over where i was testing contact notifications/modifications callbacks. Specifically the scenes contactModifyCallback was the issue:

mContactModificationCallback = new Engine::Physics::Internal::MyContactModification(wData.internalWorldData)

physx::PxSceneDesc sceneDesc;
sceneDesc.contactModifyCallback = mContactModificationCallback;
//implementation of the callback (was essentially empty/didn't do anything)
void Engine::Physics::Internal::MyContactModification::onContactModify(physx::PxContactModifyPair* const pairs, physx::PxU32 count)
{
	for (physx::PxU32 i = 0; i < count; i++)
	{
		auto& p = pairs[i];
		
		if (p.actor[0]->userData != nullptr)
		{

			for (physx::PxU32 j = 0; j < p.contacts.size(); j++)
			{

				//p.contacts.ignore(j);
				//p.contacts.set
			}
		}
	}
}
physx::PxFilterFlags DefaultFilterShader(
	physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0,
	physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1,
	physx::PxPairFlags& pairFlags, const void* constantBlock, physx::PxU32 constantBlockSize)
{
	//...
	pairFlags |= physx::PxPairFlag::eMODIFY_CONTACTS;
	//...
}

had to remove the eMODIFY_CONTACTS flag as well as remove contactModifyCallback from the scene description. (Disabling the callback entirely)

Haven't investigated the root cause yet. I suspect that the default contact processing logic required for the intended physics behaviour got ovewritten by the onContactModify function/callback (which didn't do anthing in my case.) So maybe contacts weren't flagged properly.

Here a before/after video (with the bug and after I removed the callback). Ignore the car model. This is still the exact rigidbody/cube as before just with a different visual model on it. (This is also without CCD.)

So I guess this is solved.

Thank you both for your input/directions on this quick bughunting journey. 🙂

This topic is closed to new replies.

Advertisement