I have implemented contact caching for 3D OBB collisions as in Box2D. With the prestep in Box2D, the relative velocity is not used to calculate the tangent vector, instead a scalar is crossed with the contact normal.
How do I compute the tangent vector in 3D to put in the prestep function of Box2D in the arbiters class? Initially I start off with Cross(normal, vector(1,1,1)) but this doesnt work. In using the relative velocity, initially it is parallel to the contact normal as there is no rotation of the bodies, so this returns a zero tangent vector and zero massTangent.
It's definitely the friction impulse causing erratic behaviour as I have disabled it and the normal impulse behaves correctly.
Here is my preStep function:
Code: Select all
void AMG3DRigidBodyCollisionResponder::preStep(float dt)
{
const float k_allowedPenetration = 0.01f;
float k_biasFactor = (m_bPositionCorrection) ? 0.2f : 0.0f;
if(dt<=0.0f)
return;
for(int i=0; i<m_cdContactData.iNumContacts; ++i) {
AMG3DVector4 rap = m_cdContactData.contacts[i].vContactPoint - m_pRigidBody1->position;
AMG3DVector4 rbp = m_cdContactData.contacts[i].vContactPoint - m_pRigidBody2->position;
// Precompute normal mass, tangent mass and bias
AMG3DVector4 normal = m_cdContactData.vContactNormal;
AMG3DVector4 rapcrossn = rap.cross(normal);
AMG3DVector4 rbpcrossn = rbp.cross(normal);
float Kn = m_pRigidBody1->invMass + m_pRigidBody2->invMass;
Kn += ( (m_pRigidBody1->invIWorld*rapcrossn).cross(rap) + (m_pRigidBody2->invIWorld*rbpcrossn).cross(rbp) ).dot(normal);
m_cdContactData.contacts[i].massNormal = 1.0f/Kn;
AMG3DVector4 tangent;
AMG3DVector4Cross(&tangent, normal, AMG3DVector4(1,1,1));
AMG3DVector4 rapcrosst = rap.cross(tangent);
AMG3DVector4 rbpcrosst = rbp.cross(tangent);
float Kt = m_pRigidBody1->invMass + m_pRigidBody2->invMass;
Kt += ( (m_pRigidBody1->invIWorld*rapcrosst).cross(rap) + (m_pRigidBody2->invIWorld*rbpcrosst).cross(rbp) ).dot(tangent);
m_cdContactData.contacts[i].massTangent = 1.0f/Kt;
if(m_bAccumulateImpulses) {
// Apply normal + friction impulse
AMG3DVector4 P = m_cdContactData.contacts[i].Pn * normal + m_cdContactData.contacts[i].Pt * tangent;
m_pRigidBody1->velocity += P*m_pRigidBody1->invMass;
m_pRigidBody1->angularVelocity += m_pRigidBody1->invIWorld*rap.cross(P);
m_pRigidBody2->velocity -= P*m_pRigidBody2->invMass;
m_pRigidBody2->angularVelocity -= m_pRigidBody2->invIWorld*rbp.cross(P);
}
m_cdContactData.contacts[i].bias = k_biasFactor / dt * Max(0.0f, m_cdContactData.contacts[i].fPenetrationDepth - k_allowedPenetration);
}
}