C#实现OBB碰撞算法

原理在这里
代码翻写自Simple Oriented Bounding Box OBB collision detection explaining的高赞答案(C++)

向量类Vec3

public class Vec3
{
    public float X { get; set; }
    public float Y { get; set; }
    public float Z { get; set; }
    public Vec3()
    {

    }

    public Vec3(float _x,float _y,float _z)
    {
        X = _x;
        Y = _y;
        Z = _z;
    }

    #region 操作符
    public static Vec3 operator ^(Vec3 num1, Vec3 num2)
    {
        Vec3 v = new Vec3();
        v.X = num1.Y * num2.Z - num1.Z * num2.Y;
        v.Y = num1.Z * num2.X - num1.X * num2.Z;
        v.Z = num1.X * num2.Y - num1.Y * num2.X;
        return v;
    }

    public static Vec3 operator -(Vec3 num1, Vec3 num2)
    {
        Vec3 v = new Vec3();
        v.X = num1.X-num2.X;
        v.Y = num1.Y - num2.Y;
        v.Z = num1.Z - num2.Z;
        return v;
    }

    public static float operator *(Vec3 num1, Vec3 num2)
    {
        return num1.X* num2.X + num1.Y* num2.Y+ num1.Z* num2.Z;
    }

    public static Vec3 operator *(Vec3 num1, float num2)
    {
        Vec3 v = new Vec3();
        v.X = num1.X * num2;
        v.Y = num1.Y * num2;
        v.Z = num1.Z * num2;
        return v;
    }
    #endregion
}

定义OBB模型

public class OBB
{
    public Vec3 Pos { get; set; }
    public Vec3 AxisX { get; set; }
    public Vec3 AxisY { get; set; }
    public Vec3 AxisZ { get; set; }
    public Vec3 Half_size { get; set; }
}

OBB碰撞算法

public class OBBCollision
{
    /// <summary>
    /// check if there's a separating plane in between the selected axes
    /// </summary>
    /// <returns></returns>
    public static bool GetSeparatingPlane( Vec3 RPos,  Vec3 Plane,  OBB box1,  OBB box2)
    {
        return (Math.Abs(RPos* Plane) > 
            (Math.Abs((box1.AxisX* box1.Half_size.X)*Plane) +
            Math.Abs((box1.AxisY* box1.Half_size.Y)*Plane) +
            Math.Abs((box1.AxisZ* box1.Half_size.Z)*Plane) +
            Math.Abs((box2.AxisX* box2.Half_size.X)*Plane) +
            Math.Abs((box2.AxisY* box2.Half_size.Y)*Plane) +
            Math.Abs((box2.AxisZ* box2.Half_size.Z)*Plane)));
    }

    /// <summary>
    /// test for separating planes in all 15 axes
    /// </summary>
    /// <param name="box1"></param>
    /// <param name="box2"></param>
    /// <returns></returns>
    public static bool GetCollision(OBB  box1,  OBB box2)
    {
        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));
    }
}

测试

// create two obbs
//两个OBB A和B
OBB A, B;

// set the first obb's properties
A = new OBB();
// set its center position
//定义A的中心点为(0,0,0)
A.Pos = new Vec3(0, 0, 0);

// set the half size
//定义A的1/2边长(10,1,1),即A的边长为(20,2,2)
A.Half_size = new Vec3(10, 1, 1);

// set the axes orientation
//定义A的x,y,z轴方向
A.AxisX = new Vec3(1, 0, 0);
A.AxisY = new Vec3(0, 1, 0);
A.AxisZ = new Vec3(0, 0, 1);

// set the second obb's properties
B = new OBB();
// set its center position
B.Pos = new Vec3(20, 0, 0);

// set the half size
B.Half_size = new Vec3(10, 1, 1);

// set the axes orientation
B.AxisX = new Vec3(1, 0, 0);
B.AxisY = new Vec3(0, 1, 0);
B.AxisZ = new Vec3(0, 0, 1);

// run the code and get the result as a message
if (OBBCollision.GetCollision(A, B))
{
    //碰撞
    Console.WriteLine("Collision!!!");
}
else
{
    //未碰撞
    Console.WriteLine("No collision.");
}
posted @ 2020-11-02 23:30  Lulus  阅读(1642)  评论(2编辑  收藏  举报