Sign in to follow this  
Nanook

OBB vs OBB

Recommended Posts

Nanook    537
I'm having some trouble getting my obb obb collision to work..

I've read Eberly's papers about the subject and uses his methods
and Ive used his code from geometric tools as the base for my
stuff..

I've been trying a lot for a long time now, but cant get it to work..
In my execute function the dynamicCheck function always finds the contact,
but it only manage to derive the contact data sometimes.. It seems to always
work for the first frame when the angular velocity is 0 (thats what Im using
for my rotation axis).. when it fails it reach the if (m_contactTime
<= 0.0f || side == IntersectConfig::NONE) line with both m_contactTime
set to 0 and side set to NONE..

I'm using the normalized angular velocity as the rotation axis here.. I've
also tried getting the axis from the orientation quaternion.. is this right?

Is it right to call my derrivedContacts function with the subTime? (this is
the same as the find function in Eberly's code) "The first time is computed
as the maximum time T > 0 for which there is at least one separating
axis for any t[0,T], but for which no separating axis exists at time T".. I've
tried calling with some different values too, but nothing works :/

execute()

bool Thysics::ObbObbCollider::execute()
{
//If coarse just do a quick static check.
if (m_coarse)
return staticCheck();

Thysics::PhysicsObject *physObj0 = (*m_contacts)[0].m_contactObjects[0];
Thysics::PhysicsObject *physObj1 = (*m_contacts)[0].m_contactObjects[1];

Vector3f rotAxis0 = physObj0->m_angularVelocity;
rotAxis0.Normalize();
Vector3f rotAxis1 = physObj1->m_angularVelocity;
rotAxis1.Normalize();

static int numSteps = 100;

// The time step for the integration.
float stepsize = (float)m_dt/numSteps;

// Initialize subinterval boxes.
Obb subObbs[2];
subObbs[0] = *m_obbs[0];
subObbs[1] = *m_obbs[1];

// Integrate the differential equations using Euler's method.
for (int istep = 1; istep <= numSteps; ++istep)
{
float subTime = stepsize*istep;

// Compute box velocities and test boxes for intersection.
//!!! physObj0->m_position is the rotCenter here, if center of mass is used later this needs to be changed!
Vector3f newpos0 = physObj0->m_position + subTime * physObj0->m_velocity;
Vector3f newpos1 = physObj1->m_position + subTime * physObj1->m_velocity;
Vector3f diff0 = subObbs[0].m_center - newpos0;
Vector3f diff1 = subObbs[1].m_center - newpos1;

Vector3f subVelocity0 = stepsize*(physObj0->m_velocity + rotAxis0.Cross(diff0));
Vector3f subVelocity1 = stepsize*(physObj1->m_velocity + rotAxis1.Cross(diff1));

if (dynamicCheck(stepsize, subVelocity0, subVelocity1, subObbs))
{
std::cout << "Dynamic check found contact. Deriving data...." << std::endl;
if(deriveContacts(subTime, physObj0->m_velocity, physObj1->m_velocity))
return true;
else
{
std::cout << "...could not derive contact data" << std::endl;
return false;
}
}

// Update the box centers.
subObbs[0].m_center = subObbs[0].m_center + subVelocity0;
subObbs[1].m_center = subObbs[1].m_center + subVelocity1;

// Update the box axes.
for (unsigned i = 0; i < 3; ++i)
{
subObbs[0].m_axes[i] = subObbs[0].m_axes[i] + stepsize*rotAxis0.Cross(subObbs[0].m_axes[i]);
subObbs[1].m_axes[i] = subObbs[1].m_axes[i] + stepsize*rotAxis1.Cross(subObbs[1].m_axes[i]);
}

// Use Gram-Schmidt to orthonormalize the updated axes. If
// T/N is small and N is small, this expensive call can be removed,
// assuming the updated axes are nearly orthonormal
Vector3f::Orthonormalize(subObbs[0].m_axes[0], subObbs[0].m_axes[1], subObbs[0].m_axes[2]);
Vector3f::Orthonormalize(subObbs[1].m_axes[0], subObbs[1].m_axes[1], subObbs[1].m_axes[2]);
}

return false;
}







deriveContacts()

bool Thysics::ObbObbCollider::deriveContacts(float tmax, const Vector3f& velocity0, const Vector3f& velocity1)
{
m_contactTime = 0.0f;
float tlast = FLT_MAX;

// Relative velocity of box1 relative to box0.
Vector3f relVelocity = velocity1 - velocity0;

int i0, i1;
int side = IntersectConfig::NONE;
IntersectConfig box0Cfg, box1Cfg;
Vector3f axis;

// box 0 normals
for (i0 = 0; i0 < 3; ++i0)
{
axis = m_obbs[0]->m_axes[i0];
if (!findIntersectionOnAxis(axis, m_obbs, relVelocity, tmax, m_contactTime, tlast, side, box0Cfg, box1Cfg))
return false;
}

// box 1 normals
for (i1 = 0; i1 < 3; ++i1)
{
axis = m_obbs[1]->m_axes[i1];
if (!findIntersectionOnAxis(axis, m_obbs, relVelocity, tmax, m_contactTime, tlast, side, box0Cfg, box1Cfg))
return false;
}

// box 0 edges cross box 1 edges
for (i0 = 0; i0 < 3; ++i0)
{
for (i1 = 0; i1 < 3; ++i1)
{
axis = m_obbs[0]->m_axes[i0].Cross(m_obbs[1]->m_axes[i1]);

// Since all axes are unit length (assumed), then can just compare
// against a constant (not relative) epsilon.
if (axis.SqrdLength() <= MATHS_EPSILON5)
{
// Axis i0 and i1 are parallel. If any two axes are parallel,
// then the only comparisons that needed are between the faces
// themselves. At this time the faces have already been
// tested, and without separation, so all further separation
// tests will show only overlaps.
findContactSet(m_obbs,velocity0, velocity1, side, box0Cfg, box1Cfg, m_contactTime);
return true;
}

if (!findIntersectionOnAxis(axis, m_obbs, relVelocity, tmax, m_contactTime, tlast, side, box0Cfg, box1Cfg))
return false;
}
}


// velocity cross box 0 edges
for (i0 = 0; i0 < 3; ++i0)
{
axis = relVelocity.Cross(m_obbs[0]->m_axes[i0]);
if (!findIntersectionOnAxis(axis, m_obbs, relVelocity, tmax, m_contactTime, tlast, side, box0Cfg, box1Cfg))
return false;
}

// velocity cross box 1 edges
for (i1 = 0; i1 < 3; ++i1)
{
axis = relVelocity.Cross(m_obbs[1]->m_axes[i1]);
if (!findIntersectionOnAxis(axis, m_obbs, relVelocity, tmax, m_contactTime, tlast, side, box0Cfg, box1Cfg))
return false;
}

if (m_contactTime <= 0.0f || side == IntersectConfig::NONE)
return false;

findContactSet(m_obbs, velocity0, velocity1, side, box0Cfg, box1Cfg, m_contactTime);

return true;
}






findIntersectionOnAxis()

bool Thysics::ObbObbCollider::findIntersectionOnAxis( const Vector3f& axis, const Obb *obbs[], const Vector3f& velocity, float tmax, float& tfirst, float& tlast, int& side, IntersectConfig& box0CfgFinal, IntersectConfig& box1CfgFinal )
{
IntersectConfig box0CfgStart;
box0CfgStart.setConfiguration(axis,obbs[0]);

IntersectConfig box1CfgStart;
box1CfgStart.setConfiguration(axis,obbs[1]);


// Constant velocity separating axis test. The configurations cfg0Start
// and cfg1Start are the current potential configurations for contact,
// and cfg0Final and cfg1Final are improved configurations.

float t;
float speed = axis.Dot(velocity);

if (box1CfgStart.m_max < box0CfgStart.m_min) // object1 left of object0
{
if (speed <= 0.0f) // object1 moving away from object0
return false;

// find first time of contact on this axis
t = (box0CfgStart.m_min - box1CfgStart.m_max)/speed;

// If this is the new maximum first time of contact, set side and
// configuration.
if (t > tfirst)
{
tfirst = t;
side = IntersectConfig::LEFT;
box0CfgFinal = box0CfgStart;
box1CfgFinal = box1CfgStart;
m_contactNormal = axis;
}

// quick out: intersection after desired interval
if (tfirst > tmax)
return false;

// find last time of contact on this axis
t = (box0CfgStart.m_max - box1CfgStart.m_min)/speed;
if (t < tlast)
tlast = t;

// quick out: intersection before desired interval
if (tfirst > tlast)
return false;
}
else if (box0CfgStart.m_max < box1CfgStart.m_min) // obj1 right of obj0
{
if (speed >= 0.0f) // object1 moving away from object0
return false;

// find first time of contact on this axis
t = (box0CfgStart.m_max - box1CfgStart.m_min)/speed;

// If this is the new maximum first time of contact, set side and
// configuration.
if (t > tfirst)
{
tfirst = t;
side = IntersectConfig::RIGHT;
box0CfgFinal = box0CfgStart;
box1CfgFinal = box1CfgStart;
m_contactNormal = axis;
}

// quick out: intersection after desired interval
if (tfirst > tmax)
return false;

// find last time of contact on this axis
t = (box0CfgStart.m_min - box1CfgStart.m_max)/speed;
if (t < tlast)
tlast = t;

// quick out: intersection before desired interval
if (tfirst > tlast)
return false;
}
else // object1 and object0 on overlapping interval
{
if (speed > 0.0f)
{
// find last time of contact on this axis
t = (box0CfgStart.m_max - box1CfgStart.m_min)/speed;
if (t < tlast)
{
tlast = t;
m_contactNormal = axis;
}

// quick out: intersection before desired interval
if (tfirst > tlast)
return false;
}
else if (speed < 0.0f)
{
// find last time of contact on this axis
t = (box0CfgStart.m_min - box1CfgStart.m_max)/speed;
if (t < tlast)
{
tlast = t;
m_contactNormal = axis;
}

// quick out: intersection before desired interval
if (tfirst > tlast)
return false;
}
}
return true;
}




Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this