*Bounty: 50*

I’ve been trying to get proper collision detection with SAT in 3D. I started of with this post: How many and which axes to use for 3D OBB collision with SAT.

I’ve been trying to get the right axis to test, which I thought would be correct, but they are still giving me false positives. All actual collision seem to work.

What I try is the following:

- Get the model for the objects in my game.
- Get the corners for the objects
- Adjust these corners to my object’s location
- Get the axis
- Check for overlap when projecting the corners on these axis

When positioning the object in this way:

Then I get a false positive. (Although these are axis aligned, they should be able to rotate)

I’ve been stuck on this for quit a while now, so I feel like I’m missing something I just can’t find. Also if this approach is an overkill and there is a better way, please also let me know.

I hate to just go like here’s my code, but breaking it up in pieces will probably make it more confusing, so.. here’s my code:

```
#define NOMINMAX
#include "../../stdafx.h"
#include "CollisionSystem.h"
#include "../../Core/MovingGameObject.h"
#include "../Objects/StaticObjects/Skull.h"
#include "../Objects/StaticObjects/Primitives/Plane.h"
#include <limits>
#include <cmath>
using namespace DirectX;
namespace JurreGame {
CollisionSystem::CollisionSystem()
{
}
CollisionSystem::~CollisionSystem()
{
}
void CollisionSystem::CheckCollisionBetween(GameObject* objectA, GameObject* objectB)
{
XMFLOAT4X4 modelA = objectA->GetModel();
XMMATRIX modelAMatrix = XMLoadFloat4x4(&modelA);
XMMATRIX invModel = XMMatrixInverse(&XMMatrixDeterminant(modelAMatrix), modelAMatrix);
XMFLOAT4X4 invModel4x4;
XMStoreFloat4x4(&invModel4x4, invModel);
XMMATRIX modelBMatrix = XMLoadFloat4x4(&objectB->GetModel());
XMMATRIX aAlignedObjectBModel = XMMatrixMultiply(invModel, modelBMatrix);
/* Corners positions
x y z
0 = - - +
1 = + - +
2 = + + +
3 = - + +
4 = - - -
5 = + - -
6 = + + -
7 = - + -
axis for the planes are:
X Axis => (3) - + + vs + + + (2)
Y Axis => (3) - + + vs - - + (0)
Z Axis => (3) - + + vs - + - (7)
*/
// https://gamedev.stackexchange.com/questions/44500/how-many-and-which-axis-to-use-for-3d-obb-collision-with-sat
// Get's the corners calculated for the extends.
XMFLOAT3 objectACorners[8];
objectA->bounds.GetCorners(objectACorners);
XMFLOAT3 objectBCorners[8];
objectB->bounds.GetCorners(objectBCorners);
// translates them to world space
for (int i = 0; i < 8; i++) {
XMStoreFloat3(&objectACorners[i], XMVector3Transform(XMLoadFloat3(&objectACorners[i]), modelAMatrix));
XMStoreFloat3(&objectBCorners[i], XMVector3Transform(XMLoadFloat3(&objectBCorners[i]), modelBMatrix));
}
XMVECTOR ObjectAaxis1 = XMVectorSubtract(XMLoadFloat3(&objectACorners[2]), XMLoadFloat3(&objectACorners[3]));
XMVECTOR ObjectAaxis2 = XMVectorSubtract(XMLoadFloat3(&objectACorners[3]), XMLoadFloat3(&objectACorners[0]));
XMVECTOR ObjectAaxis3 = XMVectorSubtract(XMLoadFloat3(&objectACorners[3]), XMLoadFloat3(&objectACorners[7]));
XMVECTOR ObjectBaxis1 = XMVectorSubtract(XMLoadFloat3(&objectBCorners[2]), XMLoadFloat3(&objectBCorners[3]));
XMVECTOR ObjectBaxis2 = XMVectorSubtract(XMLoadFloat3(&objectBCorners[3]), XMLoadFloat3(&objectBCorners[0]));
XMVECTOR ObjectBaxis3 = XMVectorSubtract(XMLoadFloat3(&objectBCorners[3]), XMLoadFloat3(&objectBCorners[7]));
XMVECTOR crossaxis1 = XMVector3Cross(ObjectAaxis1, ObjectBaxis1);
XMVECTOR crossaxis2 = XMVector3Cross(ObjectAaxis1, ObjectBaxis2);
XMVECTOR crossaxis3 = XMVector3Cross(ObjectAaxis1, ObjectBaxis3);
XMVECTOR crossaxis4 = XMVector3Cross(ObjectAaxis2, ObjectBaxis1);
XMVECTOR crossaxis5 = XMVector3Cross(ObjectAaxis2, ObjectBaxis2);
XMVECTOR crossaxis6 = XMVector3Cross(ObjectAaxis2, ObjectBaxis3);
XMVECTOR crossaxis7 = XMVector3Cross(ObjectAaxis3, ObjectBaxis1);
XMVECTOR crossaxis8 = XMVector3Cross(ObjectAaxis3, ObjectBaxis2);
XMVECTOR crossaxis9 = XMVector3Cross(ObjectAaxis3, ObjectBaxis3);
/**
if (HasOverlap(objectACorners, objectBCorners, ObjectAaxis1)) { OutputDebugString(L"Has overlap on ObjectAaxis1n"); }
if (HasOverlap(objectACorners, objectBCorners, ObjectAaxis2)) { OutputDebugString(L"Has overlap on ObjectAaxis2n"); }
if (HasOverlap(objectACorners, objectBCorners, ObjectAaxis3)) { OutputDebugString(L"Has overlap on ObjectAaxis3n"); }
if (HasOverlap(objectACorners, objectBCorners, ObjectBaxis1)) { OutputDebugString(L"Has overlap on ObjectBaxis1n"); }
if (HasOverlap(objectACorners, objectBCorners, ObjectBaxis2)) { OutputDebugString(L"Has overlap on ObjectBaxis2n"); }
if (HasOverlap(objectACorners, objectBCorners, ObjectBaxis3)) { OutputDebugString(L"Has overlap on ObjectBaxis3n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis1)) { OutputDebugString(L"Has overlap on crossaxis1n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis2)) { OutputDebugString(L"Has overlap on crossaxis2n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis3)) { OutputDebugString(L"Has overlap on crossaxis3n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis4)) { OutputDebugString(L"Has overlap on crossaxis4n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis5)) { OutputDebugString(L"Has overlap on crossaxis5n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis6)) { OutputDebugString(L"Has overlap on crossaxis6n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis7)) { OutputDebugString(L"Has overlap on crossaxis7n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis8)) { OutputDebugString(L"Has overlap on crossaxis8n"); }
if (HasOverlap(objectACorners, objectBCorners, crossaxis9)) { OutputDebugString(L"Has overlap on crossaxis9n"); }
*/
if (!HasOverlap(objectACorners, objectBCorners, ObjectAaxis1)) { OutputDebugString(L"No overlap on ObjectAaxis1n"); }
else if (!HasOverlap(objectACorners, objectBCorners, ObjectAaxis2)) { OutputDebugString(L"No overlap on ObjectAaxis2n"); }
else if (!HasOverlap(objectACorners, objectBCorners, ObjectAaxis3)) { OutputDebugString(L"No overlap on ObjectAaxis3n"); }
else if (!HasOverlap(objectACorners, objectBCorners, ObjectBaxis1)) { OutputDebugString(L"No overlap on ObjectBaxis1n"); }
else if (!HasOverlap(objectACorners, objectBCorners, ObjectBaxis2)) { OutputDebugString(L"No overlap on ObjectBaxis2n"); }
else if (!HasOverlap(objectACorners, objectBCorners, ObjectBaxis3)) { OutputDebugString(L"No overlap on ObjectBaxis3n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis1)) { OutputDebugString(L"No overlap on crossaxis1n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis2)) { OutputDebugString(L"No overlap on crossaxis2n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis3)) { OutputDebugString(L"No overlap on crossaxis3n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis4)) { OutputDebugString(L"No overlap on crossaxis4n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis5)) { OutputDebugString(L"No overlap on crossaxis5n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis6)) { OutputDebugString(L"No overlap on crossaxis6n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis7)) { OutputDebugString(L"No overlap on crossaxis7n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis8)) { OutputDebugString(L"No overlap on crossaxis8n"); }
else if (!HasOverlap(objectACorners, objectBCorners, crossaxis9)) { OutputDebugString(L"No overlap on crossaxis9n"); }
else {
OutputDebugString(L"Has collisionn");
}
}
bool CollisionSystem::HasOverlap(XMFLOAT3 objectACorners[], XMFLOAT3 objectBCorners[], XMVECTOR axis) {
float minA = std::numeric_limits<float>::max(), maxA = std::numeric_limits<float>::lowest();
float minB = std::numeric_limits<float>::max(), maxB = std::numeric_limits<float>::lowest();
if (XMVectorGetX(XMVector3Length(axis)) == 0.0f) {
return true;
}
for (int i = 0; i < 8; i++) {
//XMVECTOR cornerA = ProjectPoint(XMLoadFloat3(&objectACorners[i]), axis);
//float lengthA = XMVectorGetX(XMVector3Length(cornerA));
XMVECTOR dotProductA = XMVector3Dot(XMLoadFloat3(&objectACorners[i]), axis);
float lengthA = XMVectorGetX(XMVector3Length(dotProductA));
minA = fmin(minA, lengthA);
maxA = fmax(maxA, lengthA);
// XMVECTOR cornerB = ProjectPoint(XMLoadFloat3(&objectBCorners[i]), axis);
// float lengthB = XMVectorGetX(XMVector3Length(cornerB));
XMVECTOR dotProductB = XMVector3Dot(XMLoadFloat3(&objectBCorners[i]), axis);
float lengthB = XMVectorGetX(XMVector3Length(dotProductB));
minB = fmin(minB, lengthB);
maxB = fmax(maxB, lengthB);
}
float longSpan = fmax(maxA, maxB) - fmin(minA, minB);
float sumSpan = maxA - minA + maxB - minB;
return longSpan < sumSpan;
//return minB <= maxA && maxB >= minA;
}
XMVECTOR CollisionSystem::ProjectPoint(XMVECTOR point, XMVECTOR axis)
{
return (XMVector3Dot(point, axis) / XMVector3Dot(axis, axis)) * axis;
}
}
```

Get this bounty!!!