2
\$\begingroup\$

I'm trying to implement a simple OBB vs. OBB collision detection! I don't need to know where the collision occures, I only want to know whether a collision occures.

The problem is, that after lot of research in the internet I only found comments like "It's very simple, just use SAT in 3D" or some complex math. No examples anywhere!

In the best case, the algorithm should use the max/min Vectors of the boxes.

I know, that similar questions where asked before, but (I think) none of them had examples.

Apologise my bad english, I'm German and still in school! Also a reason why I want simple mathes. I hope you can help me and maybe supply me with some code.

\$\endgroup\$
1
  • \$\begingroup\$ There is no very simple OBB vs OBB collision detection algorithm. And the solution you are thinking about, i.e. with max/min vectors, applies to AABB vs AABB collision detection, not OBB vs OBB. \$\endgroup\$
    – MAnd
    Dec 12, 2015 at 18:47

2 Answers 2

2
\$\begingroup\$

Unfortunately the correct answer IS to use a complex algorithm. The two common approaches are the Separating Axis Test (SAT) or Gilbert–Johnson–Keerthi Algorithm (GJK). I would favour SAT in this case. The OBB v. OBB test is arguably the most complicated of the basic primitive collision detectors as it is a specialization of general n-face convex hull detector. Trying to cut and paste the answer onto stack exchange would be too much code. So the previous answer OBB vs OBB Collision Detection has good information and explanations.

As for working implementations, there are two that I know of:

  1. The canonical implementation in the ODE library http://www.ode.org/ in their box collider you could try adapting to your needs. It is somewhat difficult to follow but it is one of the first implementations I ever saw.

  2. Randy Gaul has a physics simulator sample that is ONLY oriented bounding boxes here https://github.com/RandyGaul/qu3e it looks modern and complete so it could be a good source.

I am sure there are others, but maybe those would work for you.

\$\endgroup\$
2
\$\begingroup\$

A C++ code implementation of the separating axis theorem for simple collision detection between two 3D OBB would be this:

#include <iostream>

// define the operations to be used in our 3D vertices
struct vec3
{
    float x, y, z;
    vec3 operator- (const vec3 & rhs) const { return{ x - rhs.x, y - rhs.y, z - rhs.z }; }
    float operator* (const vec3 & rhs) const { return{ x * rhs.x + y * rhs.y + z * rhs.z }; } // DOT PRODUCT
    vec3 operator^ (const vec3 & rhs) const { return{ y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x }; } // CROSS PRODUCT
    vec3 operator* (const float& rhs)const { return vec3{ x * rhs, y * rhs, z * rhs }; }
};

// set the relevant elements of our oriented bounding box
struct OBB
{
    vec3 Pos, AxisX, AxisY, AxisZ, Half_size;
};

// check if there's a separating plane in between the selected axes
bool getSeparatingPlane(const vec3& RPos, const vec3& Plane, const OBB& box1, const OBB&box2)
{
    return (fabs(RPos*Plane) > 
        (fabs((box1.AxisX*box1.Half_size.x)*Plane) +
        fabs((box1.AxisY*box1.Half_size.y)*Plane) +
        fabs((box1.AxisZ*box1.Half_size.z)*Plane) +
        fabs((box2.AxisX*box2.Half_size.x)*Plane) + 
        fabs((box2.AxisY*box2.Half_size.y)*Plane) +
        fabs((box2.AxisZ*box2.Half_size.z)*Plane)));
}

// test for separating planes in all 15 axes
bool getCollision(const OBB& box1, const OBB&box2)
{
    static vec3 RPos;
    RPos = box2.Pos - box1.Pos;

    return !(getSeparatingPlane(RPos, box1.AxisX, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisY, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisZ, box1, box2) ||
        getSeparatingPlane(RPos, box2.AxisX, box1, box2) ||
        getSeparatingPlane(RPos, box2.AxisY, box1, box2) ||
        getSeparatingPlane(RPos, box2.AxisZ, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisX^box2.AxisX, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisX^box2.AxisY, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisX^box2.AxisZ, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisY^box2.AxisX, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisY^box2.AxisY, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisY^box2.AxisZ, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisZ^box2.AxisX, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisZ^box2.AxisY, box1, box2) ||
        getSeparatingPlane(RPos, box1.AxisZ^box2.AxisZ, box1, box2));
}

// a quick test to see the code working
int _tmain(int argc, _TCHAR* argv[])
{
    // create two obbs
    OBB A, B;

    // set the first obb's properties
    A.Pos = { 0.f, 0.f, 0.f }; // set its center position

    // set the half size
    A.Half_size.x = 10.f; 
    A.Half_size.y = 1.f; 
    A.Half_size.z = 1.f;

    // set the axes orientation
    A.AxisX = { 1.f, 0.f, 0.f };
    A.AxisY = { 0.f, 1.f, 0.f };
    A.AxisZ = { 0.f, 0.f, 1.f };

    // set the second obb's properties
    B.Pos = { 20.f, 0.f, 0.f }; // set its center position

    // set the half size
    B.Half_size.x = 10.f;
    B.Half_size.y = 1.f;
    B.Half_size.z = 1.f;

    // set the axes orientation
    B.AxisX = { 1.f, 0.f, 0.f };
    B.AxisY = { 0.f, 1.f, 0.f };
    B.AxisZ = { 0.f, 0.f, 1.f };

    // run the code and get the result as a message
    if (getCollision(A, B)) std::cout << "Collision!!!" << std::endl;
    else std::cout << "No collision." << std::endl;

    // pause and quit
    std::cout << std::endl;
    system("pause");
    return 0;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Game Development! We generally like to see comments accompany blocs of code like this, either as an introduction, describing what's to come, or directly in the code. This will help future users understand what's going on in the code. \$\endgroup\$
    – Vaillancourt
    Jul 9, 2018 at 17:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .