in Inc/DirectXCollision.inl [3189:3357]
inline bool BoundingFrustum::Intersects(const BoundingSphere& sh) const noexcept
{
XMVECTOR Zero = XMVectorZero();
// Build the frustum planes.
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);
// Normalize the planes so we can compare to the sphere radius.
Planes[2] = XMVector3Normalize(Planes[2]);
Planes[3] = XMVector3Normalize(Planes[3]);
Planes[4] = XMVector3Normalize(Planes[4]);
Planes[5] = XMVector3Normalize(Planes[5]);
// Load origin and orientation of the frustum.
XMVECTOR vOrigin = XMLoadFloat3(&Origin);
XMVECTOR vOrientation = XMLoadFloat4(&Orientation);
assert(DirectX::Internal::XMQuaternionIsUnit(vOrientation));
// Load the sphere.
XMVECTOR vCenter = XMLoadFloat3(&sh.Center);
XMVECTOR vRadius = XMVectorReplicatePtr(&sh.Radius);
// Transform the center of the sphere into the local space of frustum.
vCenter = XMVector3InverseRotate(XMVectorSubtract(vCenter, vOrigin), vOrientation);
// Set w of the center to one so we can dot4 with the plane.
vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne());
// Check against each plane of the frustum.
XMVECTOR Outside = XMVectorFalseInt();
XMVECTOR InsideAll = XMVectorTrueInt();
XMVECTOR CenterInsideAll = XMVectorTrueInt();
XMVECTOR Dist[6];
for (size_t i = 0; i < 6; ++i)
{
Dist[i] = XMVector4Dot(vCenter, Planes[i]);
// Outside the plane?
Outside = XMVectorOrInt(Outside, XMVectorGreater(Dist[i], vRadius));
// Fully inside the plane?
InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(Dist[i], XMVectorNegate(vRadius)));
// Check if the center is inside the plane.
CenterInsideAll = XMVectorAndInt(CenterInsideAll, XMVectorLessOrEqual(Dist[i], Zero));
}
// If the sphere is outside any of the planes it is outside.
if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
return false;
// If the sphere is inside all planes it is fully inside.
if (XMVector4EqualInt(InsideAll, XMVectorTrueInt()))
return true;
// If the center of the sphere is inside all planes and the sphere intersects
// one or more planes then it must intersect.
if (XMVector4EqualInt(CenterInsideAll, XMVectorTrueInt()))
return true;
// The sphere may be outside the frustum or intersecting the frustum.
// Find the nearest feature (face, edge, or corner) on the frustum
// to the sphere.
// The faces adjacent to each face are:
static const size_t adjacent_faces[6][4] =
{
{ 2, 3, 4, 5 }, // 0
{ 2, 3, 4, 5 }, // 1
{ 0, 1, 4, 5 }, // 2
{ 0, 1, 4, 5 }, // 3
{ 0, 1, 2, 3 }, // 4
{ 0, 1, 2, 3 }
}; // 5
XMVECTOR Intersects = XMVectorFalseInt();
// Check to see if the nearest feature is one of the planes.
for (size_t i = 0; i < 6; ++i)
{
// Find the nearest point on the plane to the center of the sphere.
XMVECTOR Point = XMVectorNegativeMultiplySubtract(Planes[i], Dist[i], vCenter);
// Set w of the point to one.
Point = XMVectorInsert<0, 0, 0, 0, 1>(Point, XMVectorSplatOne());
// If the point is inside the face (inside the adjacent planes) then
// this plane is the nearest feature.
XMVECTOR InsideFace = XMVectorTrueInt();
for (size_t j = 0; j < 4; j++)
{
size_t plane_index = adjacent_faces[i][j];
InsideFace = XMVectorAndInt(InsideFace,
XMVectorLessOrEqual(XMVector4Dot(Point, Planes[plane_index]), Zero));
}
// Since we have already checked distance from the plane we know that the
// sphere must intersect if this plane is the nearest feature.
Intersects = XMVectorOrInt(Intersects,
XMVectorAndInt(XMVectorGreater(Dist[i], Zero), InsideFace));
}
if (XMVector4EqualInt(Intersects, 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);
// The Edges are:
static const size_t edges[12][2] =
{
{ 0, 1 }, { 2, 3 }, { 0, 2 }, { 1, 3 }, // Near plane
{ 4, 5 }, { 6, 7 }, { 4, 6 }, { 5, 7 }, // Far plane
{ 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 },
}; // Near to far
XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius);
// Check to see if the nearest feature is one of the edges (or corners).
for (size_t i = 0; i < 12; ++i)
{
size_t ei0 = edges[i][0];
size_t ei1 = edges[i][1];
// Find the nearest point on the edge to the center of the sphere.
// The corners of the frustum are included as the endpoints of the edges.
XMVECTOR Point = DirectX::Internal::PointOnLineSegmentNearestPoint(Corners[ei0], Corners[ei1], vCenter);
XMVECTOR Delta = XMVectorSubtract(vCenter, Point);
XMVECTOR DistSq = XMVector3Dot(Delta, Delta);
// If the distance to the center of the sphere to the point is less than
// the radius of the sphere then it must intersect.
Intersects = XMVectorOrInt(Intersects, XMVectorLessOrEqual(DistSq, RadiusSq));
}
if (XMVector4EqualInt(Intersects, XMVectorTrueInt()))
return true;
// The sphere must be outside the frustum.
return false;
}