in Inc/DirectXCollision.inl [4445:4724]
inline bool XM_CALLCONV Intersects(FXMVECTOR A0, FXMVECTOR A1, FXMVECTOR A2, GXMVECTOR B0, HXMVECTOR B1, HXMVECTOR B2) noexcept
{
static const XMVECTORU32 SelectY = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } };
static const XMVECTORU32 SelectZ = { { { XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0 } } };
static const XMVECTORU32 Select0111 = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_1, XM_SELECT_1 } } };
static const XMVECTORU32 Select1011 = { { { XM_SELECT_1, XM_SELECT_0, XM_SELECT_1, XM_SELECT_1 } } };
static const XMVECTORU32 Select1101 = { { { XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1 } } };
XMVECTOR Zero = XMVectorZero();
// Compute the normal of triangle A.
XMVECTOR N1 = XMVector3Cross(XMVectorSubtract(A1, A0), XMVectorSubtract(A2, A0));
// Assert that the triangle is not degenerate.
assert(!XMVector3Equal(N1, Zero));
// Test points of B against the plane of A.
XMVECTOR BDist = XMVector3Dot(N1, XMVectorSubtract(B0, A0));
BDist = XMVectorSelect(BDist, XMVector3Dot(N1, XMVectorSubtract(B1, A0)), SelectY);
BDist = XMVectorSelect(BDist, XMVector3Dot(N1, XMVectorSubtract(B2, A0)), SelectZ);
// Ensure robustness with co-planar triangles by zeroing small distances.
uint32_t BDistIsZeroCR;
XMVECTOR BDistIsZero = XMVectorGreaterR(&BDistIsZeroCR, g_RayEpsilon, XMVectorAbs(BDist));
BDist = XMVectorSelect(BDist, Zero, BDistIsZero);
uint32_t BDistIsLessCR;
XMVECTOR BDistIsLess = XMVectorGreaterR(&BDistIsLessCR, Zero, BDist);
uint32_t BDistIsGreaterCR;
XMVECTOR BDistIsGreater = XMVectorGreaterR(&BDistIsGreaterCR, BDist, Zero);
// If all the points are on the same side we don't intersect.
if (XMComparisonAllTrue(BDistIsLessCR) || XMComparisonAllTrue(BDistIsGreaterCR))
return false;
// Compute the normal of triangle B.
XMVECTOR N2 = XMVector3Cross(XMVectorSubtract(B1, B0), XMVectorSubtract(B2, B0));
// Assert that the triangle is not degenerate.
assert(!XMVector3Equal(N2, Zero));
// Test points of A against the plane of B.
XMVECTOR ADist = XMVector3Dot(N2, XMVectorSubtract(A0, B0));
ADist = XMVectorSelect(ADist, XMVector3Dot(N2, XMVectorSubtract(A1, B0)), SelectY);
ADist = XMVectorSelect(ADist, XMVector3Dot(N2, XMVectorSubtract(A2, B0)), SelectZ);
// Ensure robustness with co-planar triangles by zeroing small distances.
uint32_t ADistIsZeroCR;
XMVECTOR ADistIsZero = XMVectorGreaterR(&ADistIsZeroCR, g_RayEpsilon, XMVectorAbs(BDist));
ADist = XMVectorSelect(ADist, Zero, ADistIsZero);
uint32_t ADistIsLessCR;
XMVECTOR ADistIsLess = XMVectorGreaterR(&ADistIsLessCR, Zero, ADist);
uint32_t ADistIsGreaterCR;
XMVECTOR ADistIsGreater = XMVectorGreaterR(&ADistIsGreaterCR, ADist, Zero);
// If all the points are on the same side we don't intersect.
if (XMComparisonAllTrue(ADistIsLessCR) || XMComparisonAllTrue(ADistIsGreaterCR))
return false;
// Special case for co-planar triangles.
if (XMComparisonAllTrue(ADistIsZeroCR) || XMComparisonAllTrue(BDistIsZeroCR))
{
XMVECTOR Axis, Dist, MinDist;
// Compute an axis perpindicular to the edge (points out).
Axis = XMVector3Cross(N1, XMVectorSubtract(A1, A0));
Dist = XMVector3Dot(Axis, A0);
// Test points of B against the axis.
MinDist = XMVector3Dot(B0, Axis);
MinDist = XMVectorMin(MinDist, XMVector3Dot(B1, Axis));
MinDist = XMVectorMin(MinDist, XMVector3Dot(B2, Axis));
if (XMVector4GreaterOrEqual(MinDist, Dist))
return false;
// Edge (A1, A2)
Axis = XMVector3Cross(N1, XMVectorSubtract(A2, A1));
Dist = XMVector3Dot(Axis, A1);
MinDist = XMVector3Dot(B0, Axis);
MinDist = XMVectorMin(MinDist, XMVector3Dot(B1, Axis));
MinDist = XMVectorMin(MinDist, XMVector3Dot(B2, Axis));
if (XMVector4GreaterOrEqual(MinDist, Dist))
return false;
// Edge (A2, A0)
Axis = XMVector3Cross(N1, XMVectorSubtract(A0, A2));
Dist = XMVector3Dot(Axis, A2);
MinDist = XMVector3Dot(B0, Axis);
MinDist = XMVectorMin(MinDist, XMVector3Dot(B1, Axis));
MinDist = XMVectorMin(MinDist, XMVector3Dot(B2, Axis));
if (XMVector4GreaterOrEqual(MinDist, Dist))
return false;
// Edge (B0, B1)
Axis = XMVector3Cross(N2, XMVectorSubtract(B1, B0));
Dist = XMVector3Dot(Axis, B0);
MinDist = XMVector3Dot(A0, Axis);
MinDist = XMVectorMin(MinDist, XMVector3Dot(A1, Axis));
MinDist = XMVectorMin(MinDist, XMVector3Dot(A2, Axis));
if (XMVector4GreaterOrEqual(MinDist, Dist))
return false;
// Edge (B1, B2)
Axis = XMVector3Cross(N2, XMVectorSubtract(B2, B1));
Dist = XMVector3Dot(Axis, B1);
MinDist = XMVector3Dot(A0, Axis);
MinDist = XMVectorMin(MinDist, XMVector3Dot(A1, Axis));
MinDist = XMVectorMin(MinDist, XMVector3Dot(A2, Axis));
if (XMVector4GreaterOrEqual(MinDist, Dist))
return false;
// Edge (B2,B0)
Axis = XMVector3Cross(N2, XMVectorSubtract(B0, B2));
Dist = XMVector3Dot(Axis, B2);
MinDist = XMVector3Dot(A0, Axis);
MinDist = XMVectorMin(MinDist, XMVector3Dot(A1, Axis));
MinDist = XMVectorMin(MinDist, XMVector3Dot(A2, Axis));
if (XMVector4GreaterOrEqual(MinDist, Dist))
return false;
return true;
}
//
// Find the single vertex of A and B (ie the vertex on the opposite side
// of the plane from the other two) and reorder the edges so we can compute
// the signed edge/edge distances.
//
// if ( (V0 >= 0 && V1 < 0 && V2 < 0) ||
// (V0 > 0 && V1 <= 0 && V2 <= 0) ||
// (V0 <= 0 && V1 > 0 && V2 > 0) ||
// (V0 < 0 && V1 >= 0 && V2 >= 0) ) then V0 is singular;
//
// If our singular vertex is not on the positive side of the plane we reverse
// the triangle winding so that the overlap comparisons will compare the
// correct edges with the correct signs.
//
XMVECTOR ADistIsLessEqual = XMVectorOrInt(ADistIsLess, ADistIsZero);
XMVECTOR ADistIsGreaterEqual = XMVectorOrInt(ADistIsGreater, ADistIsZero);
XMVECTOR AA0, AA1, AA2;
bool bPositiveA;
if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsGreaterEqual, ADistIsLess, Select0111)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsGreater, ADistIsLessEqual, Select0111)))
{
// A0 is singular, crossing from positive to negative.
AA0 = A0; AA1 = A1; AA2 = A2;
bPositiveA = true;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsLessEqual, ADistIsGreater, Select0111)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsLess, ADistIsGreaterEqual, Select0111)))
{
// A0 is singular, crossing from negative to positive.
AA0 = A0; AA1 = A2; AA2 = A1;
bPositiveA = false;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsGreaterEqual, ADistIsLess, Select1011)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsGreater, ADistIsLessEqual, Select1011)))
{
// A1 is singular, crossing from positive to negative.
AA0 = A1; AA1 = A2; AA2 = A0;
bPositiveA = true;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsLessEqual, ADistIsGreater, Select1011)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsLess, ADistIsGreaterEqual, Select1011)))
{
// A1 is singular, crossing from negative to positive.
AA0 = A1; AA1 = A0; AA2 = A2;
bPositiveA = false;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsGreaterEqual, ADistIsLess, Select1101)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsGreater, ADistIsLessEqual, Select1101)))
{
// A2 is singular, crossing from positive to negative.
AA0 = A2; AA1 = A0; AA2 = A1;
bPositiveA = true;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsLessEqual, ADistIsGreater, Select1101)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(ADistIsLess, ADistIsGreaterEqual, Select1101)))
{
// A2 is singular, crossing from negative to positive.
AA0 = A2; AA1 = A1; AA2 = A0;
bPositiveA = false;
}
else
{
assert(false);
return false;
}
XMVECTOR BDistIsLessEqual = XMVectorOrInt(BDistIsLess, BDistIsZero);
XMVECTOR BDistIsGreaterEqual = XMVectorOrInt(BDistIsGreater, BDistIsZero);
XMVECTOR BB0, BB1, BB2;
bool bPositiveB;
if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsGreaterEqual, BDistIsLess, Select0111)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsGreater, BDistIsLessEqual, Select0111)))
{
// B0 is singular, crossing from positive to negative.
BB0 = B0; BB1 = B1; BB2 = B2;
bPositiveB = true;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsLessEqual, BDistIsGreater, Select0111)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsLess, BDistIsGreaterEqual, Select0111)))
{
// B0 is singular, crossing from negative to positive.
BB0 = B0; BB1 = B2; BB2 = B1;
bPositiveB = false;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsGreaterEqual, BDistIsLess, Select1011)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsGreater, BDistIsLessEqual, Select1011)))
{
// B1 is singular, crossing from positive to negative.
BB0 = B1; BB1 = B2; BB2 = B0;
bPositiveB = true;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsLessEqual, BDistIsGreater, Select1011)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsLess, BDistIsGreaterEqual, Select1011)))
{
// B1 is singular, crossing from negative to positive.
BB0 = B1; BB1 = B0; BB2 = B2;
bPositiveB = false;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsGreaterEqual, BDistIsLess, Select1101)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsGreater, BDistIsLessEqual, Select1101)))
{
// B2 is singular, crossing from positive to negative.
BB0 = B2; BB1 = B0; BB2 = B1;
bPositiveB = true;
}
else if (DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsLessEqual, BDistIsGreater, Select1101)) ||
DirectX::Internal::XMVector3AllTrue(XMVectorSelect(BDistIsLess, BDistIsGreaterEqual, Select1101)))
{
// B2 is singular, crossing from negative to positive.
BB0 = B2; BB1 = B1; BB2 = B0;
bPositiveB = false;
}
else
{
assert(false);
return false;
}
XMVECTOR Delta0, Delta1;
// Reverse the direction of the test depending on whether the singular vertices are
// the same sign or different signs.
if (bPositiveA ^ bPositiveB)
{
Delta0 = XMVectorSubtract(BB0, AA0);
Delta1 = XMVectorSubtract(AA0, BB0);
}
else
{
Delta0 = XMVectorSubtract(AA0, BB0);
Delta1 = XMVectorSubtract(BB0, AA0);
}
// Check if the triangles overlap on the line of intersection between the
// planes of the two triangles by finding the signed line distances.
XMVECTOR Dist0 = XMVector3Dot(Delta0, XMVector3Cross(XMVectorSubtract(BB2, BB0), XMVectorSubtract(AA2, AA0)));
if (XMVector4Greater(Dist0, Zero))
return false;
XMVECTOR Dist1 = XMVector3Dot(Delta1, XMVector3Cross(XMVectorSubtract(BB1, BB0), XMVectorSubtract(AA1, AA0)));
if (XMVector4Greater(Dist1, Zero))
return false;
return true;
}