Advertisement

OBB Collision Detection Issue

Started by February 18, 2023 04:23 AM
7 comments, last by isu diss 1 year, 7 months ago

Hi All,

I've been trying to extend Box2D Lite to 3D OBB. I've managed to detect collision between OBBs and to do contact generation. I'm not sure about the edge-edge though case and at first simulation works fine but later they sink through the ground. It worked fine with AABB. I can't seem to find the issue. Can anyone help me?

This is my arbiter code.



int Arbiter::OBBOBBIntersection(Contact *c, RigidBody *A, RigidBody *B)
{
	XMVECTOR mtvFace = XMVectorSet(0, 0, 0, 0);
	float mtdFace2 = -FLT_MAX;
	int NumContacts = 0;

	for(int i=0; i<A->GetOBB()->SupportFaceCount(); i++)
	{
		if(!TestAxis(A->GetOBB()->SupportFaceDirection(i), mtvFace, mtdFace2))
			return 0;
	}

	for(int i=0; i<B->GetOBB()->SupportFaceCount(); i++)
	{
		if(!TestAxis(B->GetOBB()->SupportFaceDirection(i), mtvFace, mtdFace2))
			return 0;
	}

	XMVECTOR mtvEdge = XMVectorSet(0, 0, 0, 0);
	float mtdEdge2 = -FLT_MAX;
	int edgeMin = 10;
	for (int i=0; i<A->GetOBB()->SupportEdgeCount(); ++i)
	{
		XMVECTOR iVec = A->GetOBB()->SupportFaceDirection(i);
		for (int j=0; j<B->GetOBB()->SupportEdgeCount(); ++j)
		{
			XMVECTOR jVec = B->GetOBB()->SupportFaceDirection(j);
			XMVECTOR crossedVec = XMVector3Normalize(XMVector3Cross(iVec, jVec));

			if(!TestAxis(crossedVec, mtvEdge, mtdEdge2))
				return 0;
			else 
				edgeMin = 3*i+j;
		}
	}

	// no intersections were ever tested.
	if(mtdFace2 < 0 && mtdEdge2 < 0)
		return 0;
	float mtdFace = sqrt(mtdFace2);
	float mtdEdge = sqrt(mtdEdge2);

	if (mtdEdge * .95 > mtdFace + .01)
	{	//Edge Collision
		XMVECTOR CollisionNormal = mtvEdge;
		contacts->normal = CollisionNormal;
            
		int axisEdge1 = edgeMin / 3;
		int axisEdge2 = edgeMin % 3;
		XMVECTOR edge1[2];
		XMVECTOR edge2[2];
		getEdge(A->GetOrientation(), *A->GetOBB(), -contacts->normal, edge1, axisEdge1, contacts[0].contactID.inI);
		getEdge(B->GetOrientation(), *B->GetOBB(), contacts->normal, edge2, axisEdge2, contacts[0].contactID.inR);
		contacts[0].position = computeContactPointEdges(edge1, edge2);
		contacts[0].separation = mtdEdge;
		contacts[0].contactID.key = 2;
		//contacts->normal *= -1;
		NumContacts = 1;
	}
	else 
	{ // Face Colision
		XMVECTOR CollisionNormal = XMVector3Normalize(-mtvFace);

		XMFLOAT3 b_vertices[] = {	XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z)
								};

		std::vector<XMFLOAT3> IncidentFace;
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == -1.0f)
		{
			IncidentFace.push_back(b_vertices[2]);
			IncidentFace.push_back(b_vertices[3]);
			IncidentFace.push_back(b_vertices[1]);
			IncidentFace.push_back(b_vertices[0]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 1.0f)
		{
			IncidentFace.push_back(b_vertices[6]);
			IncidentFace.push_back(b_vertices[7]);
			IncidentFace.push_back(b_vertices[5]);
			IncidentFace.push_back(b_vertices[4]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[4]);
			IncidentFace.push_back(b_vertices[5]);
			IncidentFace.push_back(b_vertices[3]);
			IncidentFace.push_back(b_vertices[2]);
		}
		else
		if (CollisionNormal.m128_f32[0] == -1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[0]);
			IncidentFace.push_back(b_vertices[1]);
			IncidentFace.push_back(b_vertices[7]);
			IncidentFace.push_back(b_vertices[6]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 1.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[3]);
			IncidentFace.push_back(b_vertices[5]);
			IncidentFace.push_back(b_vertices[7]);
			IncidentFace.push_back(b_vertices[1]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == -1.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[4]);
			IncidentFace.push_back(b_vertices[2]);
			IncidentFace.push_back(b_vertices[0]);
			IncidentFace.push_back(b_vertices[6]);
		}

		std::vector<Plane> ReferenceFace;
		if ((CollisionNormal.m128_f32[0] == 1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f) || (CollisionNormal.m128_f32[0] == -1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f))
		{
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,-1), -(A->GetOBB()->GetCenter().z-A->GetOBB()->GetRadius().z)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,1,0), (A->GetOBB()->GetCenter().y+A->GetOBB()->GetRadius().y)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,1), (A->GetOBB()->GetCenter().z+A->GetOBB()->GetRadius().z)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,-1,0), -(A->GetOBB()->GetCenter().y-A->GetOBB()->GetRadius().y)));
		}
		else
		if ((CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 1.0f && CollisionNormal.m128_f32[2] == 0.0f) || (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == -1.0f && CollisionNormal.m128_f32[2] == 0.0f))
		{	
			ReferenceFace.push_back(Plane(XMFLOAT3(1,0,0), (A->GetOBB()->GetCenter().x+A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,1), (A->GetOBB()->GetCenter().z+A->GetOBB()->GetRadius().z)));
			ReferenceFace.push_back(Plane(XMFLOAT3(-1,0,0), -(A->GetOBB()->GetCenter().x-A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,-1), -(A->GetOBB()->GetCenter().z-A->GetOBB()->GetRadius().z)));
		}
		else
		if ((CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 1.0f) || (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == -1.0f))
		{
			ReferenceFace.push_back(Plane(XMFLOAT3(1,0,0), (A->GetOBB()->GetCenter().x+A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,1,0), (A->GetOBB()->GetCenter().y+A->GetOBB()->GetRadius().y)));
			ReferenceFace.push_back(Plane(XMFLOAT3(-1,0,0), -(A->GetOBB()->GetCenter().x-A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,-1,0), -(A->GetOBB()->GetCenter().y-A->GetOBB()->GetRadius().y)));
		}

		if (!IncidentFace.empty() && !ReferenceFace.empty())
		{
			vector<XMFLOAT3> ContactPoints;
			ContactPoints = SHClipPolygon(IncidentFace, ReferenceFace[0]);
			if (!ContactPoints.empty())
			{
				NumContacts++;//1
				ContactPoints = SHClipPolygon(ContactPoints, ReferenceFace[1]);
				if (!ContactPoints.empty())
				{
					NumContacts++;//2
					ContactPoints = SHClipPolygon(ContactPoints, ReferenceFace[2]);
					if (!ContactPoints.empty())
					{
						NumContacts++;//3
						ContactPoints = SHClipPolygon(ContactPoints, ReferenceFace[3]);
						if (!ContactPoints.empty())
							NumContacts++;//4
					}
				}
			}
			IncidentFace.clear();
			vector<Plane>().swap(ReferenceFace);

			if (ContactPoints.empty())
				return 0;
	
			for (int i=0;i<4;i++)
			{
				c[i].normal = CollisionNormal;
				XMVECTOR TMP = XMLoadFloat3(&ContactPoints[i]);
				TMP -= CollisionNormal*mtdFace;
				XMStoreFloat3(&ContactPoints[i], TMP);
				c[i].position = XMLoadFloat3(&ContactPoints[i]);
				c[i].separation = mtdFace;
				c[i].contactID.key = 1;
			}
		}
	}
	return NumContacts;
}

XMVECTOR Arbiter::computeContactPointEdges(XMVECTOR e1[2], XMVECTOR e2[2]){
	XMVECTOR d1 = e1[1] - e1[0];
	XMVECTOR d2 = e2[1] - e2[0];
	XMVECTOR r = e1[0] - e2[0];
	float a = XMVector3Dot( d1, d1 ).m128_f32[0];
	float e = XMVector3Dot( d2, d2 ).m128_f32[0];
	float f = XMVector3Dot( d2, r ).m128_f32[0];
	float c = XMVector3Dot( d1, r ).m128_f32[0];
	float b = XMVector3Dot( d1, d2 ).m128_f32[0];
	float denom = a * e - b * b;

	float TA = (b * f - c * e) / denom;
	float TB = (b * TA + f) / e;

    return ((e1[0] + d1 * TA) + (e2[0] + d2 * TB))*.5f;
}

// Computes the edge involved in a collision given an axis and collision normal by 
// Brute forcing through the 4 possible edges to find the best support edge
void Arbiter::getEdge(XMMATRIX orientation, OBB obb, XMVECTOR normal, XMVECTOR outPoints[2], int axisEdge, int &e)
{
	normal = XMVector4Transform(normal, XMMatrixInverse(NULL, orientation));

	if (axisEdge == 0){
		XMVECTOR possiblePoints[] = {
            XMVectorSet(obb.mExtents.x, obb.mExtents.y, obb.mExtents.z, 1.0f),
            XMVectorSet(obb.mExtents.x, obb.mExtents.y, -obb.mExtents.z, 1.0f),
            XMVectorSet(obb.mExtents.x, -obb.mExtents.y, -obb.mExtents.z, 1.0f),
            XMVectorSet(obb.mExtents.x, -obb.mExtents.y, obb.mExtents.z, 1.0f)
        };

        float extremeEdge = -FLT_MAX;
        int extremeVert = 5;
        for (int x = 0; x < 4; x++){
            float temp = XMVector3Dot(possiblePoints[x], normal).m128_f32[0];
            if (temp > extremeEdge){
                extremeEdge = temp;
                extremeVert = x;
            }
        }
        outPoints[0] = possiblePoints[extremeVert];
        outPoints[1] = possiblePoints[extremeVert];
        outPoints[1].m128_f32[0] *= -1;
        e = extremeVert;
    }
    else if (axisEdge == 1){
        XMVECTOR possiblePoints[] = {
            XMVectorSet(-obb.mExtents.x, obb.mExtents.y, obb.mExtents.z, 1.0f),
            XMVectorSet(-obb.mExtents.x, obb.mExtents.y, -obb.mExtents.z, 1.0f),
            XMVectorSet(obb.mExtents.x, obb.mExtents.y, -obb.mExtents.z, 1.0f),
            XMVectorSet(obb.mExtents.x, obb.mExtents.y, obb.mExtents.z, 1.0f)
        };
        float extremeEdge = -FLT_MAX;
        int extremeVert = 5;
        for (int x = 0; x < 4; x++){
            float temp = XMVector3Dot(possiblePoints[x], normal).m128_f32[0];
            if (temp > extremeEdge){
                extremeEdge = temp;
                extremeVert = x;
            }
        }
        outPoints[0] = possiblePoints[extremeVert];
        outPoints[1] = possiblePoints[extremeVert];
        outPoints[1].m128_f32[1] *= -1;
        e = extremeVert;
    }
    else{
        XMVECTOR possiblePoints[] = {
            XMVectorSet(obb.mExtents.x, obb.mExtents.y, obb.mExtents.z, 1.0f),
            XMVectorSet(obb.mExtents.x, -obb.mExtents.y, obb.mExtents.z, 1.0f),
            XMVectorSet(-obb.mExtents.x, -obb.mExtents.y, obb.mExtents.z, 1.0f),
            XMVectorSet(-obb.mExtents.x, obb.mExtents.y, obb.mExtents.z, 1.0f)
        };
        float extremeEdge = -FLT_MAX;
        int extremeVert = 5;
        for (int x = 0; x < 4; x++){
            float temp = XMVector3Dot(possiblePoints[x], normal).m128_f32[0];
            if (temp > extremeEdge){
                extremeEdge = temp;
                extremeVert = x;
            }
        }
        outPoints[0] = possiblePoints[extremeVert];
        outPoints[1] = possiblePoints[extremeVert];
        outPoints[1].m128_f32[2] *= -1;
        e = extremeVert;
    }

    outPoints[0] = XMVector4Transform(outPoints[0], orientation);
    outPoints[1] = XMVector4Transform(outPoints[1], orientation);
    e += axisEdge * 3;
}

Arbiter::Arbiter()
{

}


Arbiter::Arbiter(RigidBody* b1, RigidBody* b2)
{
	if (b1 < b2)
	{
		body1 = b1;
		body2 = b2;
	}
	else
	{
		body1 = b2;
		body2 = b1;
	}
	restituition = /*min*/( body1->GetRestitution()* body2->GetRestitution() );

//	numContacts = AABBAABBIntersection(contacts, body1, body2);
	numContacts = OBBOBBIntersection(contacts, body1, body2);

	friction = sqrtf(body1->GetStaticFriction() * body2->GetStaticFriction());
}

void Arbiter::UpdateManifold(Contact* newContacts, int numNewContacts)
{
	Contact mergedContacts[4];

	for (int i = 0; i < numNewContacts; ++i)
	{
		Contact* cNew = newContacts + i;
		int k = -1;
		for (int j = 0; j < numContacts; ++j)
		{
			Contact* cOld = contacts + j;
			if (cNew->contactID.key == cOld->contactID.key)
			{
				k = j;
				break;
			}
		}

		if (k > -1)
		{
			Contact* c = mergedContacts + i;
			Contact* cOld = contacts + k;
			*c = *cNew;
			c->Pn = cOld->Pn;
			c->Pt[0] = cOld->Pt[0];
			c->Pt[1] = cOld->Pt[1];
		}
		else
		{
			mergedContacts[i] = newContacts[i];
		}
	}

	for (int i = 0; i < numNewContacts; ++i)
		contacts[i] = mergedContacts[i];

	numContacts = numNewContacts;
}


void Arbiter::PreStep(float inv_dt)
{
	XMVECTOR tangent[2];
	for (int i = 0; i < numContacts; ++i)
	{
		Contact* c = contacts + i;

	  XMVECTOR p = c->position;


		XMVECTOR padot = body1->GetVelocityAtPoint(p);
		XMVECTOR pbdot = body2->GetVelocityAtPoint(p);

		XMVECTOR ra = (p - body1->GetPosition());
		XMVECTOR rb = (p - body2->GetPosition());

		XMVECTOR n = c->normal;

		float C =min(0.0f, c->separation + 0.005f);
		c->bias = -inv_dt * C * .1f; 

		XMVECTOR dv = -padot +pbdot;
		float Cdot = XMVector3Dot(dv, n).m128_f32[0];
		if (Cdot < -1.0f) 
		{ 
			c->bias += -restituition * Cdot; 
		} 

		float term1 =  body1->GetMass()>0.0f ? (1.0f / body1->GetMass()) : 0.0f;
		float term2 =  body2->GetMass()>0.0f ? (1.0f / body2->GetMass()) : 0.0f;

		XMVECTOR rnA = XMVector3Cross(ra, n);
		XMVECTOR rnB = XMVector3Cross(rb, n);

		float K = term1 + term2 + XMVector3Dot(rnA, XMVector4Transform(rnA, body1->GetIInverse())).m128_f32[0] + XMVector3Dot(rnB, XMVector4Transform(rnB, body2->GetIInverse())).m128_f32[0];
		c->massNormal = K > 0.0f ? 1.0f / K : 0.0f;

		 tangent[0] = XMVector3Orthogonal(n);
		tangent[1] = XMVector3Cross(tangent[0], n);;

	/*	padot = body1->GetVelocityAtPoint(p);
		pbdot = body2->GetVelocityAtPoint(p);

			ra = (p - body1->GetPosition());
			rb = (p - body2->GetPosition());*/

			XMVECTOR rt1A = XMVector3Cross(ra, tangent[0]);
			XMVECTOR rt1B = XMVector3Cross(rb, tangent[0]);

			XMVECTOR rt2A = XMVector3Cross(ra, tangent[1]);
			XMVECTOR rt2B = XMVector3Cross(rb, tangent[1]);

			float K1 =	term1 + term2 + XMVector3Dot(rt1A, XMVector4Transform(rt1A, body1->GetIInverse())).m128_f32[0] + XMVector3Dot(rt1B, XMVector4Transform(rt1B, body2->GetIInverse())).m128_f32[0];
			float K2 = 	term1 + term2 + XMVector3Dot(rt2A, XMVector4Transform(rt2A, body1->GetIInverse())).m128_f32[0] + XMVector3Dot(rt2B, XMVector4Transform(rt2B, body2->GetIInverse())).m128_f32[0];

			c->massTangent[0] = K1 > 0.0f ? 1.0f / K1 : 0.0f;
			c->massTangent[1] = K2 > 0.0f ? 1.0f / K2 : 0.0f;

		XMVECTOR P = c->Pn * n+ c->Pt[0] * tangent[0] + c->Pt[1] * tangent[1];

		body1->AddImpulse(-P);
		body1->AddImpulsiveTorque(-XMVector3Cross(ra, P));
		body2->AddImpulse(P);
		body2->AddImpulsiveTorque(XMVector3Cross(rb, P));
	}
}

float Clamp(float a, float low, float high)
{
	return max(low, min(a, high));
}

void Arbiter::ApplyImpulse()
{
	XMVECTOR tangent[2];

	for (int i = 0; i < numContacts; ++i)
	{
		Contact* c = contacts + i;

	 XMVECTOR p = c->position;

	XMVECTOR padot = body1->GetVelocityAtPoint(p);
	XMVECTOR pbdot = body2->GetVelocityAtPoint(p);

	XMVECTOR ra = (p - body1->GetPosition());
	XMVECTOR rb = (p - body2->GetPosition());

	XMVECTOR n = c->normal;
	
	XMVECTOR dv = -padot + pbdot;

	float Cdot = XMVector3Dot(dv, n).m128_f32[0];
	float dPn = c->massNormal * (-Cdot + c->bias);

	float Pn0 = c->Pn;
	c->Pn = max(Pn0 + dPn, 0.0f);
	dPn = c->Pn - Pn0;

	XMVECTOR P = dPn * n;
	
	body1->AddImpulse(-P);
	body1->AddImpulsiveTorque(-XMVector3Cross(ra, P));
	body2->AddImpulse(P);
	body2->AddImpulsiveTorque(XMVector3Cross(rb, P));
	
//	p = c->position;

	padot = body1->GetVelocityAtPoint(p);
	pbdot = body2->GetVelocityAtPoint(p);

/*	n = c->normal;
	ra = (p - body1->GetPosition());
	rb = (p - body2->GetPosition());*/
	dv = -padot +pbdot;

	tangent[0] = XMVector3Orthogonal(n);
	tangent[1] = XMVector3Cross(tangent[0], n);

	for (int z=0;z<2;z++)
	{
		float vt = XMVector3Dot(dv, tangent[z]).m128_f32[0];
		float dPt = c->massTangent[z] * (-vt);

		// Compute friction impulse
		float maxPt = friction * c->Pn;

		// Clamp friction
		float oldTangentImpulse = c->Pt[z];
		c->Pt[z] = Clamp(oldTangentImpulse + dPt, -maxPt, maxPt);
		dPt = c->Pt[z] - oldTangentImpulse;

			// Apply contact impulse
		XMVECTOR Pt = dPt * tangent[z];

		body1->AddImpulse(-Pt);
		body1->AddImpulsiveTorque(-XMVector3Cross(ra, Pt));
		body2->AddImpulse(Pt);
		body2->AddImpulsiveTorque(XMVector3Cross(rb, Pt));
	}
	}
}

Do you use a debugger? I mean when I get problems like this, I find the simplest case that fails reliably, walk through the code step by step and look at every value. I have a scratch paper that I can write relevant numbers and information on as I go. Often, I write special routines that mimics user input, so that I can recreate the bug every run without variation caused by runtime input. If a bug seems random, you should write a logger so you can record relevant data and recreate the exact conditions where the bug occurred. Another thing you can do is have the option of turning of relevant threading, since some bugs are caused by threading, or it makes the bug even more random and harder to fix.

I'm not trying to be harsh, but it seems like debugging is becoming somewhat of a lost black art, at least in some circles. I often see code dumps on forums these days, essentially asking people to “fix my code”. While some questions regarding 3rd party APIs or algorithmic questions are valid, I would think something like this you should be able to debug on your own.

Maybe someone will come along here and do it for you, some folks seem into that. But doing it yourself will certainly give you good experience and add to your skillset. Good luck.

Advertisement

Alternatively, write and debug unit tests for all cases that can happen.

Gives good starting points for finding the bugs, and also makes more sure there are no regressions.

Most of the times I resolved bugs using debugger. Debugging the game is not possible cos it's endless (a lot of obb collisions). I've got the idea from your post @gnollrunner to write logger and go from there. Thanks guys, much obliged. In the meantime, anyone who can spot an error from the code is welcome.

What helps me a lot for debugging is visualization. In this case i would visualize the contact point, normal, and force vector.
In case you did not think on this, often it's instantly visible what's wrong.

Hi, I've written a logger. According to the logger face-face collision works fine but edge-edge collision has a bug which I can't resolve.

Log:
Sat Feb 25 11_11_17 2023 --> [FACE TEST] MTV: -0.0000000000 -0.2935402393 -0.0000000000 MTD: 0.2935402393
Sat Feb 25 11_11_17 2023 --> [EDGE TEST] MTV: 0.0000000148 -0.2936156988 0.0000000000 MTD: 0.2936156988
Sat Feb 25 11_11_17 2023 --> [FACE COLLISION] [CONTACTS] ID: 0 --> Normal: 0.0000000000 1.0000000000 0.0000000000, Position: 1.7000000477 1.0235799551 -21.5056133270, Separation: 0.2935402393
Sat Feb 25 11_11_17 2023 --> [FACE COLLISION] [CONTACTS] ID: 1 --> Normal: 0.0000000000 1.0000000000 0.0000000000, Position: 1.7000000477 1.0235799551 -20.5056133270, Separation: 0.2935402393
Sat Feb 25 11_11_17 2023 --> [FACE COLLISION] [CONTACTS] ID: 2 --> Normal: 0.0000000000 1.0000000000 0.0000000000, Position: 0.7000000477 1.0235799551 -20.5056133270, Separation: 0.2935402393
Sat Feb 25 11_11_17 2023 --> [FACE COLLISION] [CONTACTS] ID: 3 --> Normal: 0.0000000000 1.0000000000 0.0000000000, Position: 0.7000000477 1.0235799551 -21.5056133270, Separation: 0.2935402393
Sat Feb 25 11_11_17 2023 --> [FACE TEST] MTV: -0.0000000000 -0.1300445795 -0.0000000000 MTD: 0.1300445795
Sat Feb 25 11_11_17 2023 --> [EDGE TEST] MTV: 0.0075882128 -3.4401974678 0.0000000000 MTD: 3.4402058125
Sat Feb 25 11_11_17 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_17 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_17 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_17 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: -1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: -1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: -0.4964705408 -6.4696164131 20.9263515472, Edge_2_1: -0.4712062776 5.1178011894 -21.2979030609
Sat Feb 25 11_11_17 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: -0.0075882128 3.4401974678 0.0000000000, Position: -750.2453002930 -2.1346328259 11.0863838196, Separation: 3.4402058125
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: -0.0000000000 -0.0865642428 -0.0000000000 MTD: 0.0865642428
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: -0.0000000000 -4.5305156708 0.0153759606 MTD: 4.5305418968
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 0
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: 1500.0000000000 0.5000000000 1500.0000000000, Edge_1_1: 1500.0000000000 0.5000000000 -1500.0000000000, Edge_2_0: 0.5366909504 -189.7238311768 -0.1932812631, Edge_2_1: -1.6879377365 189.7150726318 -0.8926137686
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: 0.0000000000 4.5305156708 -0.0153759606, Position: 749.7365112305 -3.8987503052 -0.5275642872, Separation: 4.5305418968
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: -0.0000000000 -0.2599840164 -0.0000000000 MTD: 0.2599840164
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: -0.0000000000 7.7912616730 0.0359552540 MTD: 7.7913446426
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: 1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: 1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 1.5629096031 -191.0946502686 -1.9867537022, Edge_2_1: -2.3840310574 191.0947723389 0.8129603267
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: 0.0000000000 -7.7912616730 -0.0359552540, Position: 749.8773193359 -8.2466583252 -0.7039564848, Separation: 7.7913446426
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: -0.0000000000 -0.4389185309 -0.0000000000 MTD: 0.4389185309
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: -0.0000000000 19.8135433197 0.2764378488 MTD: 19.8154716492
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: 1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: 1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 2.1145234108 -192.4465179443 -3.9298226833, Edge_2_1: -2.5997633934 192.4622039795 2.6680696011
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: 0.0000000000 -19.8135433197 -0.2764378488, Position: 749.9943237305 -9.6859054565 -0.9544844627, Separation: 19.8154716492
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: -0.0000000000 -0.6205675602 -0.0000000000 MTD: 0.6205675602
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: -0.0000000000 31.7998065948 0.7406454682 MTD: 31.8084316254
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 1
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: 1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: 1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 1.7098200321 -193.7974395752 -5.6493148804, Edge_2_1: -3.7897269726 193.7908477783 4.7991628647
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: 0.0000000000 -31.7998065948 -0.7406454682, Position: 749.6346435547 -11.1470565796 -1.0124783516, Separation: 31.8084316254
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: -0.0000000000 -0.8049305677 -0.0000000000 MTD: 0.8049305677
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: 0.9998782277 -39.1296997070 0.0000000000 MTD: 39.1424713135
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: -1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: -1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 3.2531542778 -195.0856323242 -7.8939886093, Edge_2_1: -3.0496530533 195.1417846680 6.4568328857
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: -0.9998782277 39.1296997070 0.0000000000, Position: -750.1405029297 11.6114425659 0.1528215408, Separation: 39.1424713135
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: -0.0000000000 -0.9887682796 -0.0000000000 MTD: 0.9887682796
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: 0.8293504119 -35.7684593201 0.0000000000 MTD: 35.7780723572
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: -1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: -1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 2.5544402599 -196.4080810547 -9.6110095978, Edge_2_1: -2.0033314228 196.4832153320 8.0844879150
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: -0.8293504119 35.7684593201 0.0000000000, Position: -749.9600219727 8.2008972168 -0.0037469864, Separation: 35.7780723572
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: 0.0000000000 0.8931383491 0.0000000000 MTD: 0.8931383491
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: -0.6686856151 32.0971679688 -0.0000000000 MTD: 32.1041336060
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: -1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: -1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 1.8431458473 -197.7130126953 -11.3500194550, Edge_2_1: -0.9392569661 197.8056335449 9.7317600250
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: 0.6686856151 -32.0971679688 0.0000000000, Position: -749.8092041016 4.7774581909 -0.2757058144, Separation: 32.1041336060
Sat Feb 25 11_11_19 2023 --> [FACE TEST] MTV: 0.0000000000 0.7115808725 0.0000000000 MTD: 0.7115808725
Sat Feb 25 11_11_19 2023 --> [EDGE TEST] MTV: -0.7052896619 32.8594512939 -0.0000000000 MTD: 32.8670196533
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] AxisEdge 1: 2 Axis Edge 2: 2
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert 3
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: -1500.0000000000 -0.5000000000 1500.0000000000, Edge_1_1: -1500.0000000000 -0.5000000000 -1500.0000000000, Edge_2_0: 1.6717855930 -198.9865875244 -13.2573966980, Edge_2_1: -0.4102697372 199.0998687744 11.5450382233
Sat Feb 25 11_11_19 2023 --> [EDGE COLLISION] [CONTACTS] --> Normal: 0.7052896619 -32.8594512939 0.0000000000, Position: -749.7036743164 3.4241790771 -0.4019260406, Separation: 32.8670196533

After adding logger code:

bool Arbiter::TestAxis(XMVECTOR axis, XMVECTOR& mtv, float& mtd)
{
	// intervals along axis
	float mina, maxa;
	float minb, maxb;
	float tolerance = 1.0e-8f;

	float d = XMVector3Dot(axis, axis).m128_f32[0];
	if(d < tolerance)
		return false;

//	body1->GetAABB()->supportInterval(axis, mina, maxa);
//	body2->GetAABB()->supportInterval(axis, minb, maxb);
	body1->GetOBB()->SupportInterval(axis, mina, maxa);
	body2->GetOBB()->SupportInterval(axis, minb, maxb);

	// calculate the two possible overlap ranges.
	// either we overlap on the left or right sides.
	float d0 = (maxb - mina); // 'left' side
	float d1 = (maxa - minb); // 'right' side

	// intervals do not overlap. no intersection.
    if(d0 < tolerance || d1 < tolerance)
		return false;
		
	// find out if we overlap on the 'right' or 'left' of the object.
	float overlap = (d0 < d1) ? d0 : -d1;
	// the mtv for that axis
	XMVECTOR sep = axis * (overlap / d);

	// the mtv length squared.
	float sep_length = XMVector3Length(sep).m128_f32[0];

	// in the mtv along axis the minimum among all push vectors
	// or we haven't computed a push vector yet, use this as our best candidate.
	if (sep_length < mtd || mtd < 0.0f)
	{
		mtd = sep_length;
		mtv  = sep;
	}
	return true;
}


int Arbiter::OBBOBBIntersection(Contact *c, RigidBody *A, RigidBody *B)
{
	XMVECTOR mtvFace = XMVectorSet(0, 0, 0, 0);
	float mtdFace = -FLT_MAX;
	int NumContacts = 0;
	char str[512];

    XMVECTOR RelativePosition = B->GetPosition() - A->GetPosition();

	for(int i=0; i<A->GetOBB()->SupportFaceCount(); i++)
	{
		if(!TestAxis(A->GetOBB()->SupportFaceDirection(i), mtvFace, mtdFace))
			return 0;
	}

	for(int i=0; i<B->GetOBB()->SupportFaceCount(); i++)
	{
		if(!TestAxis(B->GetOBB()->SupportFaceDirection(i), mtvFace, mtdFace))
			return 0;
	}

	sprintf_s(str, "[FACE TEST] MTV: %.10f %.10f %.10f MTD: %.10f", mtvFace.m128_f32[0], mtvFace.m128_f32[1], mtvFace.m128_f32[2], mtdFace);
	string tmp(str);
	RELog::GetInstance()->WriteMessage(tmp);

	XMVECTOR mtvEdge = XMVectorSet(0, 0, 0, 0);
	float mtdEdge = -FLT_MAX;
	int edgeMin = 10;
	for (int i=0; i<A->GetOBB()->SupportEdgeCount(); ++i)
	{
		XMVECTOR iVec = A->GetOBB()->SupportFaceDirection(i);
		for (int j=0; j<B->GetOBB()->SupportEdgeCount(); ++j)
		{
			XMVECTOR jVec = B->GetOBB()->SupportFaceDirection(j);
			XMVECTOR crossedVec = XMVector3Normalize(XMVector3Cross(iVec, jVec));

			if(!TestAxis(crossedVec, mtvEdge, mtdEdge))
				return 0;
			else 
				edgeMin = 3*i+j;
		}
	}

	sprintf_s(str, "[EDGE TEST] MTV: %.10f %.10f %.10f MTD: %.10f", mtvEdge.m128_f32[0], mtvEdge.m128_f32[1], mtvEdge.m128_f32[2], mtdEdge);
	string tmp2(str);
	RELog::GetInstance()->WriteMessage(tmp2);

	// no intersections were ever tested.
	//if(mtdFace2 < 0 && mtdEdge2 < 0)
//		return 0;
//	if(mtdFace < 0 && mtdEdge < 0)
//		return 0;

	if (mtdEdge * .95 > mtdFace + .01)
	{	//Edge Collision
		contacts->normal = -mtvEdge;
            
		int axisEdge1 = edgeMin / 3;
		int axisEdge2 = edgeMin % 3;
		sprintf_s(str, "[EDGE COLLISION] AxisEdge 1: %d Axis Edge 2: %d", axisEdge1, axisEdge2);
		string tmp1(str);
		RELog::GetInstance()->WriteMessage(tmp1);

		XMVECTOR edge1[2];
		XMVECTOR edge2[2];
		getEdge(A->GetOrientation(), *A->GetOBB(), -contacts->normal, edge1, axisEdge1);
		getEdge(B->GetOrientation(), *B->GetOBB(), contacts->normal, edge2, axisEdge2);
		sprintf_s(str, "[EDGE COLLISION] [SUPPORTEDGES] --> Edge_1_0: %.10f %.10f %.10f, Edge_1_1: %.10f %.10f %.10f, Edge_2_0: %.10f %.10f %.10f, Edge_2_1: %.10f %.10f %.10f", edge1[0].m128_f32[0], edge1[0].m128_f32[1], edge1[0].m128_f32[2], edge1[1].m128_f32[0], edge1[1].m128_f32[1], edge1[1].m128_f32[2], edge2[0].m128_f32[0], edge2[0].m128_f32[1], edge2[0].m128_f32[2], edge2[1].m128_f32[0], edge2[1].m128_f32[1], edge2[1].m128_f32[2]);
		string tmp3(str);
		RELog::GetInstance()->WriteMessage(tmp3);

		contacts[0].position = computeContactPointEdges(edge1, edge2);
		contacts[0].separation = mtdEdge;
		contacts[0].contactID.key = 2;
//		contacts->normal *= -1;
		NumContacts = 1;

		sprintf_s(str, "[EDGE COLLISION] [CONTACTS] --> Normal: %.10f %.10f %.10f, Position: %.10f %.10f %.10f, Separation: %.10f", contacts->normal.m128_f32[0], contacts->normal.m128_f32[1], contacts->normal.m128_f32[2], contacts->position.m128_f32[0], contacts->position.m128_f32[1], contacts->position.m128_f32[2], contacts->separation);
		string tmp2(str);
		RELog::GetInstance()->WriteMessage(tmp2);

	}
	else 
	{ // Face Colision
		XMVECTOR CollisionNormal = XMVector3Normalize(-mtvFace);

		XMFLOAT3 b_vertices[] = {	XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z-B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x+B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y-B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z),
									XMFLOAT3(B->GetOBB()->GetCenter().x-B->GetOBB()->GetRadius().x, B->GetOBB()->GetCenter().y+B->GetOBB()->GetRadius().y, B->GetOBB()->GetCenter().z+B->GetOBB()->GetRadius().z)
								};

		std::vector<XMFLOAT3> IncidentFace;
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == -1.0f)
		{
			IncidentFace.push_back(b_vertices[2]);
			IncidentFace.push_back(b_vertices[3]);
			IncidentFace.push_back(b_vertices[1]);
			IncidentFace.push_back(b_vertices[0]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 1.0f)
		{
			IncidentFace.push_back(b_vertices[6]);
			IncidentFace.push_back(b_vertices[7]);
			IncidentFace.push_back(b_vertices[5]);
			IncidentFace.push_back(b_vertices[4]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[4]);
			IncidentFace.push_back(b_vertices[5]);
			IncidentFace.push_back(b_vertices[3]);
			IncidentFace.push_back(b_vertices[2]);
		}
		else
		if (CollisionNormal.m128_f32[0] == -1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[0]);
			IncidentFace.push_back(b_vertices[1]);
			IncidentFace.push_back(b_vertices[7]);
			IncidentFace.push_back(b_vertices[6]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 1.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[3]);
			IncidentFace.push_back(b_vertices[5]);
			IncidentFace.push_back(b_vertices[7]);
			IncidentFace.push_back(b_vertices[1]);
		}
		else
		if (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == -1.0f && CollisionNormal.m128_f32[2] == 0.0f)
		{
			IncidentFace.push_back(b_vertices[4]);
			IncidentFace.push_back(b_vertices[2]);
			IncidentFace.push_back(b_vertices[0]);
			IncidentFace.push_back(b_vertices[6]);
		}

		std::vector<Plane> ReferenceFace;
		if ((CollisionNormal.m128_f32[0] == 1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f) || (CollisionNormal.m128_f32[0] == -1.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 0.0f))
		{
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,-1), -(A->GetOBB()->GetCenter().z-A->GetOBB()->GetRadius().z)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,1,0), (A->GetOBB()->GetCenter().y+A->GetOBB()->GetRadius().y)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,1), (A->GetOBB()->GetCenter().z+A->GetOBB()->GetRadius().z)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,-1,0), -(A->GetOBB()->GetCenter().y-A->GetOBB()->GetRadius().y)));
		}
		else
		if ((CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 1.0f && CollisionNormal.m128_f32[2] == 0.0f) || (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == -1.0f && CollisionNormal.m128_f32[2] == 0.0f))
		{	
			ReferenceFace.push_back(Plane(XMFLOAT3(1,0,0), (A->GetOBB()->GetCenter().x+A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,1), (A->GetOBB()->GetCenter().z+A->GetOBB()->GetRadius().z)));
			ReferenceFace.push_back(Plane(XMFLOAT3(-1,0,0), -(A->GetOBB()->GetCenter().x-A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,0,-1), -(A->GetOBB()->GetCenter().z-A->GetOBB()->GetRadius().z)));
		}
		else
		if ((CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == 1.0f) || (CollisionNormal.m128_f32[0] == 0.0f && CollisionNormal.m128_f32[1] == 0.0f && CollisionNormal.m128_f32[2] == -1.0f))
		{
			ReferenceFace.push_back(Plane(XMFLOAT3(1,0,0), (A->GetOBB()->GetCenter().x+A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,1,0), (A->GetOBB()->GetCenter().y+A->GetOBB()->GetRadius().y)));
			ReferenceFace.push_back(Plane(XMFLOAT3(-1,0,0), -(A->GetOBB()->GetCenter().x-A->GetOBB()->GetRadius().x)));
			ReferenceFace.push_back(Plane(XMFLOAT3(0,-1,0), -(A->GetOBB()->GetCenter().y-A->GetOBB()->GetRadius().y)));
		}

		if (!IncidentFace.empty() && !ReferenceFace.empty())
		{
			vector<XMFLOAT3> ContactPoints;
			ContactPoints = SHClipPolygon(IncidentFace, ReferenceFace[0]);
			if (!ContactPoints.empty())
			{
				NumContacts++;//1
				ContactPoints = SHClipPolygon(ContactPoints, ReferenceFace[1]);
				if (!ContactPoints.empty())
				{
					NumContacts++;//2
					ContactPoints = SHClipPolygon(ContactPoints, ReferenceFace[2]);
					if (!ContactPoints.empty())
					{
						NumContacts++;//3
						ContactPoints = SHClipPolygon(ContactPoints, ReferenceFace[3]);
						if (!ContactPoints.empty())
							NumContacts++;//4
					}
				}
			}
			IncidentFace.clear();
			vector<Plane>().swap(ReferenceFace);

			if (ContactPoints.empty())
				return 0;
	
			for (int i=0;i<ContactPoints.size();i++)
			{
				c[i].normal = CollisionNormal;
				XMVECTOR TMP = XMLoadFloat3(&ContactPoints[i]);
				TMP -= CollisionNormal*mtdFace;
				XMStoreFloat3(&ContactPoints[i], TMP);
				c[i].position = XMLoadFloat3(&ContactPoints[i]);
				c[i].separation = mtdFace;
				c[i].contactID.key = 1;

				sprintf_s(str, "[FACE COLLISION] [CONTACTS] ID: %d --> Normal: %.10f %.10f %.10f, Position: %.10f %.10f %.10f, Separation: %.10f", i, contacts[i].normal.m128_f32[0], contacts[i].normal.m128_f32[1], contacts[i].normal.m128_f32[2], contacts[i].position.m128_f32[0], contacts[i].position.m128_f32[1], contacts[i].position.m128_f32[2], contacts[i].separation);
				string tmp(str);
				RELog::GetInstance()->WriteMessage(tmp);
			}
		}
	}
	return NumContacts;
}

XMVECTOR Arbiter::computeContactPointEdges(XMVECTOR e1[2], XMVECTOR e2[2]){
	XMVECTOR d1 = e1[1] - e1[0];
	XMVECTOR d2 = e2[1] - e2[0];
	XMVECTOR r = e1[0] - e2[0];
	float a = XMVector3Dot( d1, d1 ).m128_f32[0];
	float e = XMVector3Dot( d2, d2 ).m128_f32[0];
	float f = XMVector3Dot( d2, r ).m128_f32[0];
	float c = XMVector3Dot( d1, r ).m128_f32[0];
	float b = XMVector3Dot( d1, d2 ).m128_f32[0];
	float denom = a * e - b * b;

	float TA = (b * f - c * e) / denom;
	float TB = (b * TA + f) / e;

    return ((e1[0] + d1 * TA) + (e2[0] + d2 * TB))*.5f;
}

// Computes the edge involved in a collision given an axis and collision normal by 
// Brute forcing through the 4 possible edges to find the best support edge

void Arbiter::getEdge(XMMATRIX orientation, OBB obb, XMVECTOR normal, XMVECTOR outPoints[2], int axisEdge)
{
	char str[256];

	normal = XMVector4Transform(normal, orientation);

	if (axisEdge == 0){
        XMVECTOR possiblePoints[] = {
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z-obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y-obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y-obb.mExtents.y, obb.GetCenter().z-obb.mExtents.z, 1.0f)
        };
        float extremeEdge = -FLT_MAX;
        int extremeVert = 5;
        for (int x = 0; x < 4; x++){
            float temp = XMVector3Dot(possiblePoints[x], normal).m128_f32[0];
            if (temp < extremeEdge || extremeEdge< 0.0f){
                extremeEdge = temp;
                extremeVert = x;
            }
        }
		sprintf_s(str, "[EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert %d", extremeVert);
		string tmp3(str);
		RELog::GetInstance()->WriteMessage(tmp3);

        outPoints[0] = possiblePoints[extremeVert];
        outPoints[1] = possiblePoints[extremeVert];
        outPoints[1].m128_f32[0] *= -1;
    }
    else if (axisEdge == 1){
        XMVECTOR possiblePoints[] = {
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z-obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x-obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x-obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z-obb.mExtents.z, 1.0f)
        };
        float extremeEdge = -FLT_MAX;
        int extremeVert = 5;
        for (int x = 0; x < 4; x++){
            float temp = XMVector3Dot(possiblePoints[x], normal).m128_f32[0];
            if (temp < extremeEdge || extremeEdge< 0.0f){
                extremeEdge = temp;
                extremeVert = x;
            }
        }
		sprintf_s(str, "[EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert %d", extremeVert);
		string tmp3(str);
		RELog::GetInstance()->WriteMessage(tmp3);

        outPoints[0] = possiblePoints[extremeVert];
        outPoints[1] = possiblePoints[extremeVert];
        outPoints[1].m128_f32[1] *= -1;
    }
    else{
        XMVECTOR possiblePoints[] = {
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x-obb.mExtents.x, obb.GetCenter().y+obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x+obb.mExtents.x, obb.GetCenter().y-obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f),
            XMVectorSet(obb.GetCenter().x-obb.mExtents.x, obb.GetCenter().y-obb.mExtents.y, obb.GetCenter().z+obb.mExtents.z, 1.0f)
        };
        float extremeEdge = -FLT_MAX;
        int extremeVert = 5;
        for (int x = 0; x < 4; x++){
            float temp = XMVector3Dot(possiblePoints[x], normal).m128_f32[0];
            if (temp < extremeEdge || extremeEdge< 0.0f){
                extremeEdge = temp;
                extremeVert = x;
            }
        }
		sprintf_s(str, "[EDGE COLLISION] [SUPPORTEDGES] --> Extreme Vert %d", extremeVert);
		string tmp3(str);
		RELog::GetInstance()->WriteMessage(tmp3);

        outPoints[0] = possiblePoints[extremeVert];
        outPoints[1] = possiblePoints[extremeVert];
        outPoints[1].m128_f32[2] *= -1;
    }

    outPoints[0] = XMVector4Transform(outPoints[0], orientation);
    outPoints[1] = XMVector4Transform(outPoints[1], orientation);
}

Here's the simulation: its log is attached above. https://www.youtube.com/watch?v=Z9xv2I6Psag

Advertisement
  1. Make a setup that reliably reproduces the same bug every time you run it,
  2. Find the line with the first wrong result in the log.
  3. Step through the code with a debugger until you are close to the wrong result. (simplest is perhaps to set a breakpoint at or just after the log call before the bad line).
  4. Verify results of each statement as you step through the statements.
  5. Before the log call that will print the wrong result you should find something wrong. If not, you missed something, try again,
  6. You found the statement that produced the wrong result. Check and fix it!
  7. Done!

EDIT: Actually, point 7 is optimistic, you should run the code again after the fix and check it does the right thing. If it doesn't more things are wrong. Go back to step 1 for finding/fixing the next problem.

It took me while but I found the bug and fixed it. I rewrote most of the code for general solution. Above code is not valid anymore. Thanks.

This topic is closed to new replies.

Advertisement