欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-13 13:52:52
...

原理: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;
}

 

相关标签: 3D图形 OpenGL