inline bool BoundingFrustum::Intersects()

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;
}