in Inc/DirectXCollision.inl [3786:3931]
inline bool XM_CALLCONV BoundingFrustum::Intersects(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept
{
// Build the frustum planes (NOTE: D is negated from the usual).
XMVECTOR Planes[6];
Planes[0] = XMVectorSet(0.0f, 0.0f, -1.0f, -Near);
Planes[1] = XMVectorSet(0.0f, 0.0f, 1.0f, Far);
Planes[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f);
Planes[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f);
Planes[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f);
Planes[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f);
// Load origin and orientation of the frustum.
XMVECTOR vOrigin = XMLoadFloat3(&Origin);
XMVECTOR vOrientation = XMLoadFloat4(&Orientation);
assert(DirectX::Internal::XMQuaternionIsUnit(vOrientation));
// Transform triangle into the local space of frustum.
XMVECTOR TV0 = XMVector3InverseRotate(XMVectorSubtract(V0, vOrigin), vOrientation);
XMVECTOR TV1 = XMVector3InverseRotate(XMVectorSubtract(V1, vOrigin), vOrientation);
XMVECTOR TV2 = XMVector3InverseRotate(XMVectorSubtract(V2, vOrigin), vOrientation);
// Test each vertex of the triangle against the frustum planes.
XMVECTOR Outside = XMVectorFalseInt();
XMVECTOR InsideAll = XMVectorTrueInt();
for (size_t i = 0; i < 6; ++i)
{
XMVECTOR Dist0 = XMVector3Dot(TV0, Planes[i]);
XMVECTOR Dist1 = XMVector3Dot(TV1, Planes[i]);
XMVECTOR Dist2 = XMVector3Dot(TV2, Planes[i]);
XMVECTOR MinDist = XMVectorMin(Dist0, Dist1);
MinDist = XMVectorMin(MinDist, Dist2);
XMVECTOR MaxDist = XMVectorMax(Dist0, Dist1);
MaxDist = XMVectorMax(MaxDist, Dist2);
XMVECTOR PlaneDist = XMVectorSplatW(Planes[i]);
// Outside the plane?
Outside = XMVectorOrInt(Outside, XMVectorGreater(MinDist, PlaneDist));
// Fully inside the plane?
InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(MaxDist, PlaneDist));
}
// If the triangle is outside any of the planes it is outside.
if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
return false;
// If the triangle is inside all planes it is fully inside.
if (XMVector4EqualInt(InsideAll, XMVectorTrueInt()))
return true;
// Build the corners of the frustum.
XMVECTOR vRightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f);
XMVECTOR vRightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f);
XMVECTOR vLeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f);
XMVECTOR vLeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f);
XMVECTOR vNear = XMVectorReplicatePtr(&Near);
XMVECTOR vFar = XMVectorReplicatePtr(&Far);
XMVECTOR Corners[CORNER_COUNT];
Corners[0] = XMVectorMultiply(vRightTop, vNear);
Corners[1] = XMVectorMultiply(vRightBottom, vNear);
Corners[2] = XMVectorMultiply(vLeftTop, vNear);
Corners[3] = XMVectorMultiply(vLeftBottom, vNear);
Corners[4] = XMVectorMultiply(vRightTop, vFar);
Corners[5] = XMVectorMultiply(vRightBottom, vFar);
Corners[6] = XMVectorMultiply(vLeftTop, vFar);
Corners[7] = XMVectorMultiply(vLeftBottom, vFar);
// Test the plane of the triangle.
XMVECTOR Normal = XMVector3Cross(XMVectorSubtract(V1, V0), XMVectorSubtract(V2, V0));
XMVECTOR Dist = XMVector3Dot(Normal, V0);
XMVECTOR MinDist, MaxDist;
MinDist = MaxDist = XMVector3Dot(Corners[0], Normal);
for (size_t i = 1; i < CORNER_COUNT; ++i)
{
XMVECTOR Temp = XMVector3Dot(Corners[i], Normal);
MinDist = XMVectorMin(MinDist, Temp);
MaxDist = XMVectorMax(MaxDist, Temp);
}
Outside = XMVectorOrInt(XMVectorGreater(MinDist, Dist), XMVectorLess(MaxDist, Dist));
if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
return false;
// Check the edge/edge axes (3*6).
XMVECTOR TriangleEdgeAxis[3];
TriangleEdgeAxis[0] = XMVectorSubtract(V1, V0);
TriangleEdgeAxis[1] = XMVectorSubtract(V2, V1);
TriangleEdgeAxis[2] = XMVectorSubtract(V0, V2);
XMVECTOR FrustumEdgeAxis[6];
FrustumEdgeAxis[0] = vRightTop;
FrustumEdgeAxis[1] = vRightBottom;
FrustumEdgeAxis[2] = vLeftTop;
FrustumEdgeAxis[3] = vLeftBottom;
FrustumEdgeAxis[4] = XMVectorSubtract(vRightTop, vLeftTop);
FrustumEdgeAxis[5] = XMVectorSubtract(vLeftBottom, vLeftTop);
for (size_t i = 0; i < 3; ++i)
{
for (size_t j = 0; j < 6; j++)
{
// Compute the axis we are going to test.
XMVECTOR Axis = XMVector3Cross(TriangleEdgeAxis[i], FrustumEdgeAxis[j]);
// Find the min/max of the projection of the triangle onto the axis.
XMVECTOR MinA, MaxA;
XMVECTOR Dist0 = XMVector3Dot(V0, Axis);
XMVECTOR Dist1 = XMVector3Dot(V1, Axis);
XMVECTOR Dist2 = XMVector3Dot(V2, Axis);
MinA = XMVectorMin(Dist0, Dist1);
MinA = XMVectorMin(MinA, Dist2);
MaxA = XMVectorMax(Dist0, Dist1);
MaxA = XMVectorMax(MaxA, Dist2);
// Find the min/max of the projection of the frustum onto the axis.
XMVECTOR MinB, MaxB;
MinB = MaxB = XMVector3Dot(Axis, Corners[0]);
for (size_t k = 1; k < CORNER_COUNT; k++)
{
XMVECTOR Temp = XMVector3Dot(Axis, Corners[k]);
MinB = XMVectorMin(MinB, Temp);
MaxB = XMVectorMax(MaxB, Temp);
}
// if (MinA > MaxB || MinB > MaxA) reject;
Outside = XMVectorOrInt(Outside, XMVectorGreater(MinA, MaxB));
Outside = XMVectorOrInt(Outside, XMVectorGreater(MinB, MaxA));
}
}
if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
return false;
// If we did not find a separating plane then the triangle must intersect the frustum.
return true;
}