长方体不会始终与轴对齐。如何确定它们是否相互交叉?
答案 0 :(得分:2)
分离轴定理(http://en.wikipedia.org/wiki/Separating_axis_theorem)确保在你的情况下(两个长方体) 如果它们不相交,则存在分离平面。因此,众所周知的方法是投影立方体顶点(甚至是Oriented Bounding Box顶点,而不假设它是立方体) 到每个可能的分离轴。立方体的面和成对的交叉乘积都有法线。
设N1,N2,N3为第一个立方体面的法线,M1,M2,M3为第二个立方体面的法线。设A和B. 分别是第一和第二个立方体的中心。
然后你必须将第一个立方体的每个点投影到N1,N2,N3,M1,M2,M3,N1xM1,N1xM2等。
然后检查投影点与另一个立方体中心之间的距离。
C ++中的完整代码(对于vec3类型有一些明显的运算符重载):
bool Intersection_BoxToBox( const Box& ABox, const Box& BBox )
{
float R, R0, R1;
eBoxSeparatingAxis SeparatingAxis = S_AXIS_NONE;
float AxisLen, TmpDepth;
/// Relative distance
LVector3 D = BBox.FCenter - ABox.FCenter;
SeparatingAxis = S_AXIS_NONE;
/// Test each separating plane with Axes A0..A2, B0..B2 (six cases)
#define TEST_SEP_PLANE( PARAM_AxisName, PARAM_RelativeVal, PARAM_R0, PARAM_R1, PARAM_Normal ) \
R = fabs(PARAM_RelativeVal); \
R0 = PARAM_R0; \
R1 = PARAM_R1; \
/* If (R>R0+R1) Then there is no intersection */\
TmpDepth = R0 + R1 - R; \
if (TmpDepth < 0) return false; \
\
if (MaxDepth > TmpDepth) { \
MaxDepth = TmpDepth; \
SeparatingAxis = PARAM_AxisName; \
}
float a0 = ABox.FExtent[0];
float a1 = ABox.FExtent[1];
float a2 = ABox.FExtent[2];
float b0 = BBox.FExtent[0];
float b1 = BBox.FExtent[1];
float b2 = BBox.FExtent[2];
/// 1. A0
float A0D = ABox.FAxis[0].Dot( D );
float c00 = ABox.FAxis[0].Dot( BBox.FAxis[0] );
float c01 = ABox.FAxis[0].Dot( BBox.FAxis[1] );
float c02 = ABox.FAxis[0].Dot( BBox.FAxis[2] );
TEST_SEP_PLANE( S_AXIS_A0, A0D, a0, b0 * fabs( c00 ) + b1 * fabs( c01 ) + b2 * fabs( c02 ), ABox.FAxis[0] )
/// 2. A1
float A1D = D.Dot( ABox.FAxis[1] );
float c10 = ABox.FAxis[1].Dot( BBox.FAxis[0] );
float c11 = ABox.FAxis[1].Dot( BBox.FAxis[1] );
float c12 = ABox.FAxis[1].Dot( BBox.FAxis[2] );
TEST_SEP_PLANE( S_AXIS_A1, A1D, a1, b0 * fabs( c10 ) + b1 * fabs( c11 ) + b2 * fabs( c12 ), ABox.FAxis[1] )
/// 3. A2
float A2D = ABox.FAxis[2].Dot( D );
float c20 = ABox.FAxis[2].Dot( BBox.FAxis[0] );
float c21 = ABox.FAxis[2].Dot( BBox.FAxis[1] );
float c22 = ABox.FAxis[2].Dot( BBox.FAxis[2] );
TEST_SEP_PLANE( S_AXIS_A2, A2D, a2, b0 * fabs( c20 ) + b1 * fabs( c21 ) + b2 * fabs( c22 ), ABox.FAxis[2] )
/// 4. B0
float B0D = BBox.FAxis[0].Dot( D );
TEST_SEP_PLANE( S_AXIS_B0, B0D, a0 * fabs( c00 ) + a1 * fabs( c01 ) + a2 * fabs( c02 ), b0, BBox.FAxis[0] )
/// 5. B1
float B1D = BBox.FAxis[1].Dot( D );
TEST_SEP_PLANE( S_AXIS_B1, B1D, a0 * fabs( c10 ) + a1 * fabs( c11 ) + a2 * fabs( c12 ), b1, BBox.FAxis[1] )
/// 6. B2
float B2D = BBox.FAxis[2].Dot( D );
TEST_SEP_PLANE( S_AXIS_B2, B2D, a0 * fabs( c20 ) + a1 * fabs( c21 ) + a2 * fabs( c22 ), b2, BBox.FAxis[2] )
#undef TEST_SEP_PLANE
/// Now we test the cross-product axes
#define TEST_SEP_AXIS( PARAM_AxisName, PARAM_DirA, PARAM_DirB, PARAM_RelativeVal, PARAM_R0, PARAM_R1) \
TempAxis = PARAM_DirA .Cross( PARAM_DirB ); \
AxisLen = TempAxis.SqrLength(); \
\
if ( AxisLen > ::Math::EPSILON) \
{ \
R = PARAM_RelativeVal; \
R0 = PARAM_R0; \
R1 = PARAM_R1; \
\
TmpDepth = R0 + R1 - fabs(R); \
if (TmpDepth < 0) return false; \
\
if (MaxDepth * AxisLen > TmpDepth ) \
{ \
MaxDepth = TmpDepth / AxisLen; \
SeparatingAxis = PARAM_AxisName; \
} \
}
/// 7.-15. Name DirA DirB RelVal R0 R1
TEST_SEP_AXIS( S_AXIS_A0B0, ABox.FAxis[0], BBox.FAxis[0] , c10 * A2D - c20 * A1D, a1 * fabs( c20 ) + a2 * fabs( c10 ), b1 * fabs( c02 ) + b2 * fabs( c01 ) )
TEST_SEP_AXIS( S_AXIS_A0B1, ABox.FAxis[0], BBox.FAxis[1] , c11 * A2D - c21 * A1D, a1 * fabs( c21 ) + a2 * fabs( c11 ), b0 * fabs( c02 ) + b2 * fabs( c00 ) )
TEST_SEP_AXIS( S_AXIS_A0B2, ABox.FAxis[0], BBox.FAxis[2] , c12 * A2D - c22 * A1D, a1 * fabs( c22 ) + a2 * fabs( c12 ), b0 * fabs( c01 ) + b1 * fabs( c00 ) )
TEST_SEP_AXIS( S_AXIS_A1B0, ABox.FAxis[1], BBox.FAxis[0] , c20 * A0D - c00 * A2D, a0 * fabs( c20 ) + a2 * fabs( c00 ), b1 * fabs( c12 ) + b2 * fabs( c11 ) )
TEST_SEP_AXIS( S_AXIS_A1B1, ABox.FAxis[1], BBox.FAxis[1] , c21 * A0D - c01 * A2D, a0 * fabs( c21 ) + a2 * fabs( c01 ), b0 * fabs( c12 ) + b2 * fabs( c10 ) )
TEST_SEP_AXIS( S_AXIS_A1B2, ABox.FAxis[1], BBox.FAxis[2] , c22 * A0D - c02 * A2D, a0 * fabs( c22 ) + a2 * fabs( c02 ), b0 * fabs( c11 ) + b1 * fabs( c10 ) )
TEST_SEP_AXIS( S_AXIS_A2B0, ABox.FAxis[2], BBox.FAxis[0] , c00 * A1D - c10 * A0D, a0 * fabs( c10 ) + a1 * fabs( c00 ), b1 * fabs( c22 ) + b2 * fabs( c21 ) )
TEST_SEP_AXIS( S_AXIS_A2B1, ABox.FAxis[2], BBox.FAxis[1] , c01 * A1D - c11 * A0D, a0 * fabs( c11 ) + a1 * fabs( c01 ), b0 * fabs( c22 ) + b2 * fabs( c20 ) )
TEST_SEP_AXIS( S_AXIS_A2B2, ABox.FAxis[2], BBox.FAxis[2] , c02 * A1D - c12 * A0D, a0 * fabs( c12 ) + a1 * fabs( c02 ), b0 * fabs( c21 ) + b1 * fabs( c20 ) )
if ( SeparatingAxis == S_AXIS_NONE ) { return false; }
#undef TEST_SEP_AXIS
return true;
}
答案 1 :(得分:0)
您首先要确定其中一个长方体的方向。然后将其他坐标转换为该坐标系。您还可以使用第一个长方体的尺寸来轻松设置每个轴上长方体左/内/右边的点的条件。
现在很容易检查是否
如果每个顶点对的每个坐标对(在每个维度中)都在(左右和左右),则包含长方体,而不是包含(。)