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.");
}
学习技术最好的文档就是【官方文档】,没有之一。
还有学习资料【Microsoft Learn】、【CSharp Learn】、【My Note】。
如果,你认为阅读这篇博客让你有些收获,不妨点击一下右下角的【推荐】按钮。
如果,你希望更容易地发现我的新博客,不妨点击一下【关注】。