Page 1 of 3

Rigid body box stacking

Posted: Tue Jan 28, 2014 10:16 pm
by c0der
Hi,

I have got my clipping algorithm to work (I zero'd the collision velocities and drew the contact manifold to show this). Now I am having trouble with overshoot. I am using the interpenetration depth of each contact, which should technically be correct. I also have implemented warm starting I tried implementing the bias from Erin Catto's presentations but am still getting overshoot. Please help!

Here is the rest of the code, it doesn't let me paste it here.
http://codepad.org/JJhSuL2p

Code: Select all


void AMG3DRigidBodyCollisionResponder::computeMasses(const AMG3DScalar& dt)
{
	if(m_bSkipCollision)
		return;

	if(dt<=0.0f)
		return;

	const AMG3DScalar k_allowedPenetration = 0.01f;
	AMG3DScalar k_biasFactor = (AMG3DPhysicsWorld::g_AMG3D_bPositionCorrection) ? 0.2f : 0.0f;

	for(int i=0; i<m_cdContactData.iNumContacts; ++i) {
		AMG3DVector4 normal = m_cdContactData.contacts[i].vContactNormal;

		AMG3DVector4 rap = m_cdContactData.contacts[i].vContactPoint - m_pRigidBody1->m_vPosition;
		AMG3DVector4 rbp = m_cdContactData.contacts[i].vContactPoint - m_pRigidBody2->m_vPosition;

		AMG3DVector4 rapcrossn = rap.cross(normal);
		AMG3DVector4 rbpcrossn = rbp.cross(normal);

		// Compute the normal mass
		AMG3DScalar Kn = m_pRigidBody1->m_sInvMass + m_pRigidBody2->m_sInvMass;
		Kn += ( (m_pRigidBody1->m_matInvIWorld*rapcrossn).cross(rap) + (m_pRigidBody2->m_matInvIWorld*rbpcrossn).cross(rbp) ).dot(normal);
		m_cdContactData.contacts[i].massNormal = 1.0f/Kn;

		// Compute the bias (prevents sinking, useful for stacking)
		m_cdContactData.contacts[i].bias = k_biasFactor / dt * 
							AMG3D_MATH_MAX(0.0f, m_cdContactData.contacts[i].sPenetrationDepth - k_allowedPenetration);

		// Calculate the tangent vector. To Do: Research relative velocity tangent vector
		//AMG3DVector4 vabn = normal*(vab.dot(normal));
		//AMG3DVector4 vabt = vab - vabn;
		AMG3DVector4 t1, t2;

		//if(vabt.magnitude()>0) {
		//	vabt.normalize();
		//	t1 = vabt;
		//	AMG3DVector4Cross(&t2, normal, t1);
		//}
		//else {
			normal.buildOrthoBasis(&t1, &t2);
		//}

		AMG3DVector4 rapcrosst1 = rap.cross(t1);
		AMG3DVector4 rbpcrosst1 = rbp.cross(t1);

		// Compute the tangent mass in the first direction
		AMG3DScalar Kt1 = m_pRigidBody1->m_sInvMass + m_pRigidBody2->m_sInvMass;
		Kt1 += ( (m_pRigidBody1->m_matInvIWorld*rapcrosst1).cross(rap) + (m_pRigidBody2->m_matInvIWorld*rbpcrosst1).cross(rbp) ).dot(t1);
		m_cdContactData.contacts[i].massTangent1 = 1.0f/Kt1;

		AMG3DVector4 rapcrosst2 = rap.cross(t2);
		AMG3DVector4 rbpcrosst2 = rbp.cross(t2);

		// Compute the tangent mass in the second direction
		AMG3DScalar Kt2 = m_pRigidBody1->m_sInvMass + m_pRigidBody2->m_sInvMass;
		Kt2 += ( (m_pRigidBody1->m_matInvIWorld*rapcrosst2).cross(rap) + (m_pRigidBody2->m_matInvIWorld*rbpcrosst2).cross(rbp) ).dot(t2);
		m_cdContactData.contacts[i].massTangent2 = 1.0f/Kt2;
	
		if(AMG3DPhysicsWorld::g_AMG3D_bWarmStarting) {
			AMG3DVector4 P = m_cdContactData.contacts[i].Pn*normal + m_cdContactData.contacts[i].Pt1*t1 + m_cdContactData.contacts[i].Pt2*t2;

			m_pRigidBody1->m_vVelocity			+= P*m_pRigidBody1->m_sInvMass;
			m_pRigidBody1->m_vAngularVelocity	+= m_pRigidBody1->m_matInvIWorld*rap.cross(P);
		
			m_pRigidBody2->m_vVelocity			-= P*m_pRigidBody2->m_sInvMass;
			m_pRigidBody2->m_vAngularVelocity	-= m_pRigidBody2->m_matInvIWorld*rbp.cross(P);
		}	
	}
}


Re: Rigid body box stacking

Posted: Wed Jan 29, 2014 5:49 pm
by Dirk Gregorius
Difficult to say without debugging this. I would check that all signs are correct. Disable stabilization and see if you get correct stacking with some sinking, but without overshoot. Finally make sure that you get the correct penetration depth. If you use MPR instead of SAT this will be very likely the reason.

In my experience one expects some dramatic mistake when things like this happen, but it is often just some tiny error. Setup the simplest scene that shows the erratic behavior and then step through it.

Re: Rigid body box stacking

Posted: Wed Jan 29, 2014 5:50 pm
by Dirk Gregorius
Oh, and for warmstarting you need to project the last friction impulses onto the new basis. But this is unrelated to your problem.

Essentially:

Vector Pt = Pt1 + Pt2;
float lambda1 = dot( Pt, t1 );
float lambda2 = dot( Pt, t2 );

Vector new_Pt1 = lambda1 * t1;
Vector new_Pt2 = lambda2 * t2;

Re: Rigid body box stacking

Posted: Wed Jan 29, 2014 5:55 pm
by Dirk Gregorius
Here is how you compute the relative velocity in the tangent plane:

You know that: v_rel = vn + vt
Here vn is the relative velocity in the direction of the normal and vt is the relative velocity in the tangent plane. Both quantities are vectors. Since we know the contact normal we can build vn = dot( v_rel, n ) * n
Finally you identify vt = v_rel - vt

Now |vt| can be zero and in this case you still need to fall back on your ortho basis.

This seems to be what your were trying to do. So if this is not working there might be some mistake elsewhere.

Re: Rigid body box stacking

Posted: Wed Jan 29, 2014 9:47 pm
by c0der
Thanks Dirk. I am using SAT and have some snapshots. I am trying 5 boxes now. I zero the collision velocities (EngineZeroCV.png) and the boxes are coming in fairly straight. When I enable impulses and disable position correction (EngineZero.png), I get an uneven effect, but this should be OK as the corrective impulses will handle this. One thing I notice is when I use a minimum penetration depth for all contacts, it's more stable, but I don't think this is correct. I am actually not using constraints but just a regular impulse resolver.

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 12:39 am
by RandyGaul
Dirk Gregorius wrote:Here is how you compute the relative velocity in the tangent plane:

You know that: v_rel = vn + vt
Here vn is the relative velocity in the direction of the normal and vt is the relative velocity in the tangent plane. Both quantities are vectors. Since we know the contact normal we can build vn = dot( v_rel, n ) * n
Finally you identify vt = v_rel - vt

Now |vt| can be zero and in this case you still need to fall back on your ortho basis.

This seems to be what your were trying to do. So if this is not working there might be some mistake elsewhere.
Do you recommend this projection? A lot of students I talk to prefer to keep an arbitrary othonormal basis for friction axes rather than computing friction tangents aligned by the relative motion.

In my own simulation this style is very stable, but I have seen Erwin on these forums state that if an object slides quickly along a plane one of the friction axes can converge before the other causing an arced path of travel. I haven't noticed this artifact myself though.

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 12:57 am
by Dirk Gregorius
Personally I use a totally different friction model so I cannot really recommend something here. If you use the velocity projection you need to make sure to also project the accumulated friction impulses onto the new tangent axes as I have shown above. If you don't project onto the new axes you might get artifacts with warmstarting. This is often overlooked and might be the reason why some students prefer the fixed axes where the direction hardly changes and you will not notice any problems. Aligning with the tangential velocity should be better, but I am not sure if you will notice any difference for stacking. You need to test this in some sliding test cases. The theoretical concerns you mention are true and I have seen these artifacts in practice as well.

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 12:59 am
by Dirk Gregorius
@Coder: The problems you are seeing might be due to the variable timestep. You would need to scale the accumulated impulse by the ratio of the last and current timestep for warmstarting. Personally I would not use a varying timestep at all.

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 1:55 am
by c0der
I actually mean by "variable timestep" the one I implemented from gafferongames. I am currently using a fixed timestep and still have the same problem. I disabled position correction and the jitter stopped, I am about to give up, been stuck for a while now. Also, I disabled friction.

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 4:23 am
by c0der
Actually now I realise why I didn't use the relative velocity, it's because I would then have to recompute the tangent masses as each iteration. I think the problem is in building the ortho basis at each frame for each contact, this means that for each contact, the tangent impulses won't be coplanar. With Erin Catto's 2D version, he doesn't use relative velocity, just directly get the tangent vector and computes this and the tangent mass once per frame.

Any tips on porting this to 3D avoiding computing the tangent mass per iteration?

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 4:28 am
by Dirk Gregorius
You only compute the friction basis once before starting to iterate. Either from the relative velocity or just from the normal. The normal doesn't change during the iteration so no need to recompute the basis. Even if you use the relative velocity you just do it once and then stick with this basis.

Re: Rigid body box stacking

Posted: Thu Jan 30, 2014 4:25 pm
by bone
RandyGaul wrote:In my own simulation this style is very stable, but I have seen Erwin on these forums state that if an object slides quickly along a plane one of the friction axes can converge before the other causing an arced path of travel. I haven't noticed this artifact myself though.
Like Dirk and Erwin, I've seen the "arc" as well when not using relative velocity as one of the orthonormal bases.

Re: Rigid body box stacking

Posted: Fri Jan 31, 2014 12:44 am
by c0der
I combined the tangent vectors into 1 for both directions t1+t2. Now I am getting sliding problems, the overshoot is gone. I will deal with the arc later if it comes up, I am using an ortho basis computed from the normal for now

Re: Rigid body box stacking

Posted: Fri Jan 31, 2014 12:51 am
by RandyGaul
c0der wrote:I combined the tangent vectors into 1 for both directions t1+t2. Now I am getting sliding problems, the overshoot is gone. I will deal with the arc later if it comes up, I am using an ortho basis computed from the normal for now
It does not make sense to me to model coulomb friction with a single vector as you need a 3D friction plane. If you generate an orthonormal basis (perhaps via cross product) given an input normal you can use the two generated vectors as friction axes. Have you tried this?

As a side note to the arc artifact: I've written simulations used in multiple student projects and done a lot of personal testing and have yet to actually notice any artifacts; I don't really think it's something anyone should worry about until it becomes a priority.

Re: Rigid body box stacking

Posted: Fri Jan 31, 2014 1:07 am
by Dirk Gregorius
I have tested this in real production code that actually shipped and trust me it is a real world problem. If you want to push an object from A to B in a game and it moves on an arc rather than a straight line this will be indeed a problem. If objects slide on planes and actually also rotate around the up-axis that is a problem. Sorry student projects and personal testing don't count! :) You also might want to come up with better test cases!