CSC8503_Advanced_Game_Technologies / CSC8503 / CSC8503Common / SATAlgorithm.cpp
SATAlgorithm.cpp
Raw
#include "SATAlgorithm.h"
#include "Debug.h"
using namespace NCL;
#include "Transform.h"

using namespace Maths;
using namespace CSC8503;

SATAlgorithm::SATAlgorithm()
{
}


SATAlgorithm::~SATAlgorithm()
{
}

bool SATAlgorithm::BoundingBoxSAT(const NCL::OBBVolume& volumeA, const Transform& worldTransformA,
	const NCL::OBBVolume& volumeB, const Transform& worldTransformB, CollisionDetection::CollisionInfo& collisionInfo
) {
	Vector3 aBoxSize = volumeA.GetHalfDimensions();// * 0.5f;
	Vector3 bBoxSize = volumeB.GetHalfDimensions();// * 0.5f;

	Matrix3 aInvOrientation = Matrix3(worldTransformA.GetOrientation().Conjugate());

	Vector3 bRelativePos = aInvOrientation * (worldTransformB.GetPosition() - worldTransformA.GetPosition());

	Matrix3 relativeOrientation = aInvOrientation * Matrix3(worldTransformB.GetOrientation());
	Matrix3 absoluteRelative = relativeOrientation.Absolute();

	//Vector3 bBoxExpanded = absoluteRelative * bBoxSize; //need to see how to use this better

	Vector3 realRelativeSize = relativeOrientation * bBoxSize;

	//box a can now be thought of as being axis aligned to b

	bool isParallel = false;

	for (int i = 0; i < 9; ++i) {
		if (absoluteRelative.array[i] > 0.999f) {
			isParallel = true;
			break;
		}
	}

	float bestOnA = -FLT_MAX;
	float bestOnB = -FLT_MAX;
	float bestOnEdge = -FLT_MAX;

	int bestAAxis = 0;
	int bestBAxis = 0;

	bool noCollide = false;

	//Test A axes
	for (int i = 0; i < 3; ++i) {
		float s = abs(bRelativePos[i]) - (aBoxSize[i] + Vector3::Dot(absoluteRelative.GetRow(i), bBoxSize));

		if (s > 0.0f) {
			noCollide = true;
			//definately not colliding, there's a separation on this axis
		}

		if (s > bestOnA) {
			bestOnA = s;
			bestAAxis = i;
		}
	}

	//Now test B Axes
	for (int i = 0; i < 3; ++i) {

		float s = abs(Vector3::Dot(bRelativePos, relativeOrientation.GetColumn(i))) - (bBoxSize[i] + Vector3::Dot(absoluteRelative.GetColumn(i), aBoxSize));

		if (s > 0.0f) {
			noCollide = true;
			//definately not colliding, there's a separation on this axis
		}

		if (s > bestOnB) {
			bestOnB = s;
			bestBAxis = i;
		}
	}

	//Now we have to also check the edges

	Vector3 bestEdgeAxis;
	if (!isParallel) {
		for (int a = 0; a < 3; ++a) {
			Vector3 aDir = absoluteRelative.GetColumn(a);
			for (int b = 0; b < 3; ++b) {
				Vector3 bDir = relativeOrientation.GetColumn(b);

				Vector3 l = Vector3::Cross(aDir, bDir);

				if (l.Length() == 0.0f) {
					continue;
				}

				float tl = Vector3::Dot(bRelativePos, l);
				float al = Vector3::Dot(aBoxSize, l);
				float bl = Vector3::Dot(realRelativeSize, l);

				float s = abs(tl) - (abs(al) + abs(bl));

				if (s > 0.0f) {
					noCollide = true;//definately not colliding, there's a separation on this axis
				}
				if (s > bestOnEdge) {
					bestOnEdge = s;
					//bestAAxis	= a;
					//bestBAxis	= b;
					bestEdgeAxis = l;
				}
			}
		}
	}

	Vector3 aNorm = Vector3(worldTransformA.GetMatrix().GetColumn(bestAAxis));
	Vector3 otherA = aInvOrientation.GetColumn(bestAAxis);

	Vector3 bNorm = Vector3(worldTransformB.GetMatrix().GetColumn(bestBAxis));
	Vector3 edgeNorm = bestEdgeAxis;

	Debug::DrawLine(worldTransformA.GetPosition(), worldTransformA.GetPosition() + (aNorm  * bestOnA * 0.5f), Vector4(1, 0, 0, 1));
	Debug::DrawLine(worldTransformA.GetPosition(), worldTransformA.GetPosition() + (otherA  * bestOnA * 0.5f), Vector4(0.5, 0, 0, 1));

	Debug::DrawLine(worldTransformB.GetPosition(), worldTransformB.GetPosition() + (bNorm  * bestOnB * 0.5f), Vector4(1, 1, 0, 1));


	//float bestFace = max(bestOnA, bestOnB);

	//if (bestOnEdge > bestFace) {
	//	Vector3 norm = bestEdgeAxis;
	//	Debug::DrawLine(worldTransformA.GetWorldPosition(), worldTransformA.GetWorldPosition() + (norm  * 15.0f), Vector4(1, 0, 0, 1));
	//}
	//else {
	//	if (bestOnA > bestOnB) {
	//		Vector3 norm = worldTransformA.GetWorldMatrix().GetColumn(bestAAxis).ToVector3();
	//		Debug::DrawLine(worldTransformA.GetWorldPosition(), worldTransformA.GetWorldPosition() + (norm  * 15.0f), Vector4(1, 0, 0, 1));
	//	}
	//	else {
	//		Vector3 bNorm = worldTransformB.GetWorldMatrix().GetColumn(bestBAxis).ToVector3();
	//		Debug::DrawLine(worldTransformB.GetWorldPosition(), worldTransformB.GetWorldPosition() + (bNorm  * 15.0f), Vector4(1, 0, 0, 1));
	//	}
	//}

	////Vector3 aNorm = worldTransformA.GetWorldMatrix().GetColumn(bestAAxis).ToVector3();
	////
	////Vector3 edgeNorm = bestEdgeAxis;

	////Vector3 lolTest = Vector3::Cross(aNorm, bNorm);
	//Vector3 bNorm = worldTransformB.GetWorldMatrix().GetColumn(bestBAxis).ToVector3();
	////Debug::DrawLine(worldTransformA.GetWorldPosition(), worldTransformA.GetWorldPosition() + (aNorm  * 15.0f), Vector4(1, 0, 0, 1));
	//Debug::DrawLine(worldTransformB.GetWorldPosition(), worldTransformB.GetWorldPosition() + (bNorm  * 15.0f), Vector4(1, 1, 0, 1));

	////Debug::DrawLine(worldTransformA.GetWorldPosition(), worldTransformA.GetWorldPosition() + (lolTest  * 15.0f), Vector4(0.2, 0.1, 0.8, 1));

	//////Debug::DrawLine(worldTransformA.GetWorldPosition(), worldTransformA.GetWorldPosition() + (edgeNorm  * 15.0f), Vector4(0, 1, 1, 1));


	if (noCollide) {
		return false;
	}

	float bestFace = max(bestOnA, bestOnB);

	//if (noCollide) {
	//	std::cout << "SAT NO COLLIDE?" << std::endl;
	//}

	if (bestOnEdge > bestFace) {
		std::cout << "SAT EDGE COLLISION " << bestOnEdge << std::endl;
	}
	else {
		std::cout << "SAT FACE COLLISION " << bestFace << std::endl;
	}
	return true;
}

void SATAlgorithm::OBBSupport(Vector3& min, Vector3& max, const Vector3& objectPos, const Vector3& axis) {
	Vector3 tangents[2];

	//tangents[0] = 

}