OBB方向包围盒碰撞检测算法(原理与代码)

原理:OBB间的相交测试基于分离轴理论(separating axis theory)。若两个OBB在一条轴线上(不一定是坐标轴)上的投影不重叠,则这条轴称为分离轴。若一对OBB间存在一条分离轴,则可以判定这两个OBB不相交。对任何两个不相交的凸三维多面体,其分离轴要么垂直于任何一个多面体的某一个面,要么同时垂直于每个多面体的某一条边。因此,对一对OBB,只需测试15条可能是分离轴的轴(每个OBB的3个面方向再加上每个OBB的3个边方面的两两组合),只要找到一条这样的分离轴,就可以判定这两个OBB是不相交的,如果这15条轴都不能将这两个OBB分离,则它们是相交的。 

 

代码:

FBox,FOrientedBox都是UE4数据结构
/**@前路漫漫 oriented box intersection */
bool IntersectOOBB(const FOrientedBox& OB1, const FOrientedBox& OB2)
{
	const int32 ObVertNum = 8;
	FVector OB1Vert[ObVertNum] = { FVector::ZeroVector };
	OB1.CalcVertices(OB1Vert);

	FVector OB2Vert[ObVertNum] = { FVector::ZeroVector };
	OB2.CalcVertices(OB2Vert);

	//calculate 1d bound box
	auto affectMinMaxValue = [](float& min, float& max, float value)
	{
		min = std::min(min, value);
		max = std::max(max, value);
	};

	//determin whether two obb(box1, box2) exit a separate axis on a given axis(axe)
	auto isSATFoundedOnAxe = [&affectMinMaxValue, &OB1Vert, &OB2Vert, &ObVertNum](const FOrientedBox& box1, const FOrientedBox& box2, const FVector& axe)->bool
	{
		float minBox1 = std::numeric_limits<float>::max(), maxBox1 = std::numeric_limits<float>::min(), minBox2 = std::numeric_limits<float>::max(), maxBox2 = std::numeric_limits<float>::min();

		for (int32 i = 0; i < ObVertNum; i++)
		{
			affectMinMaxValue(minBox1, maxBox1, axe | OB1Vert[i]);
		}

		for (int32 i = 0; i < ObVertNum; i++)
		{
			affectMinMaxValue(minBox2, maxBox2, axe | OB2Vert[i]);
		}

		//try seg1 on seg2 or seg2 on seg1
		return ((minBox2 <= maxBox1 && minBox2 >= minBox1) ||
			(maxBox2 <= maxBox1 && maxBox2 >= minBox1)) ||
			((minBox1 <= maxBox2 && minBox1 >= minBox2) ||
				(maxBox1 <= maxBox2 && maxBox1 >= minBox2));
	};

	/*Exclude the majority case of no collision*/
	FBox Box1AABB(OB1Vert, ObVertNum);
	FBox Box2AABB(OB2Vert, ObVertNum);
	if (!Box1AABB.Intersect(Box2AABB))
		return false;

	/*Use SAT to know if collision existe*/
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisX)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisY)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisZ)) return false;

	if (!isSATFoundedOnAxe(OB1, OB2, OB2.AxisX)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB2.AxisY)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB2.AxisZ)) return false;

	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisX ^ OB2.AxisX)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisX ^ OB2.AxisY)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisX ^ OB2.AxisZ)) return false;

	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisY ^ OB2.AxisX)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisY ^ OB2.AxisY)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisY ^ OB2.AxisZ)) return false;

	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisZ ^ OB2.AxisX)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisZ ^ OB2.AxisY)) return false;
	if (!isSATFoundedOnAxe(OB1, OB2, OB1.AxisZ ^ OB2.AxisZ)) return false;

	return true;
}

 

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
OBB碰撞检测算法原理是基于包围相交检测,通过判断两个旋转的包围是否相交来确定碰撞情况。 以下是OBB碰撞检测算法的基本原理: 1. 包围定义:每个物体(例如车辆)都被定义为一个旋转的包围,通常是一个矩形或长方体。包围由中心点、尺寸(长度、宽度和高度)和旋转角度(通常表示为欧拉角或四元数)来确定。 2. 包围的表示:包围可以使用矩阵变换来表示。通过将包围的中心和尺寸与旋转矩阵相乘,可以将包围从局部坐标系转换到世界坐标系。 3. 碰撞检测:通过检测两个包围是否相交来判断碰撞情况。两个包围相交的条件是:它们在三个坐标轴上的投影相交。即,两个包围在X轴、Y轴和Z轴上的投影都有重叠部分。 4. 投影检测:为了检测投影是否相交,可以使用包围的顶点或边在投影轴上的最小和最大值。通过计算两个包围在每个轴上的投影,并比较它们的最小和最大值,可以确定是否相交。 使用OBB碰撞检测算法时,需要注意以下几点: - 确定包围的正确性和准确性,以确保它们能够正确地表示物体的形状和方向。 - 选择合适的碰撞检测策略,可以采用分离轴定理(Separating Axis Theorem)或其他相应的算法来进行检测。 - 在实际应用中,可能需要考虑包围的更新和优化策略,以提高碰撞检测的效率和准确性。 总之,OBB碰撞检测算法通过比较旋转的包围在各个轴上的投影,来判断物体之间是否发生碰撞。这种算法在自动驾驶等领域中被广泛应用于车辆碰撞检测和避免碰撞的实现。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值