对于布尔查询,请使用 Laurence 的答案。它也可以用于移动框,但是你必须使用二进制搜索来找到交点或时间间隔。
求解轴上相交的参数化时间
如果您想要可移动的盒子,另一种解决方案是根据行进方向分别找到每个轴上发生交叉点的参数时间。我们将框 A 和 B 称为最小值和最大值的极值点。您只需要一个方向,因为您可以从 B 的方向中减去 A 的方向并留下一个向量。所以你可以认为B是移动的,A是静止的。我们将方向称为 D。求解 t 给出:
(用于沿 D 的交叉点的起点)
Bmax + tEnterD = Amin
tEnterD = Amin - Bmax
tEnter = (Amin - Bmax) / D
(沿 D 的交叉点的末端;A 的背面)
Bmin + tLeaveD = Amax
tLeaveD = Amax - Bmin
tLeave = (Amax - Bmin) / D
在每个轴上执行此检查,如果它们都重叠,则您有一个交叉点。如果分母为零,则该轴上有无限重叠或没有重叠。如果 tEnter 大于 1 或 tLeave 小于 0,则重叠比方向长度更远,或者方向错误。
bool IntersectAxis(float min1, float max1, float min2, float max2,
float diraxis, float& tEnter, float& tLeave)
{
const float intrEps = 1e-9;
/* Carefully check for diraxis==0 using an epsilon. */
if( std::fabs(diraxis) < intrEps ){
if((min1 >= max2) || (max1 <= min2)){
/* No movement in the axis, and they don't overlap,
hence no intersection. */
return false;
} else {
/* Stationary in the axis, with overlap at t=0 to t=1 */
return true;
}
} else {
float start = (min1 - max2) / diraxis;
float leave = (max1 - min2) / diraxis;
/* Swap to make sure our intervals are correct */
if(start > leave)
std::swap(start,leave);
if(start > tEnter)
tEnter = start;
if(leave < tLeave)
tLeave = leave;
if(tEnter > tLeave)
return false;
}
return true;
}
bool Intersect(const AABB& b1, const AABB& b2, Vector3 dir, float& tEnter, float& tLeave)
{
tEnter = 0.0f;
tLeave = 1.0f;
if(IntersectAxis(b1.bmin.x, b1.bmax.x, b2.bmin.x, b2.bmax.x, dir.x, tEnter, tLeave) == false)
return false;
else if(IntersectAxis(b1.bmin.y, b1.bmax.y, b2.bmin.y, b2.bmax.y, dir.y, tEnter, tLeave) == false)
return false;
else if(IntersectAxis(b1.bmin.z, b1.bmax.z, b2.bmin.z, b2.bmax.z, dir.z, tEnter, tLeave) == false)
return false;
else
return true;
}