inline bool BoundingFrustum::Intersects()

in Inc/DirectXCollision.inl [3568:3779]


inline bool BoundingFrustum::Intersects(const BoundingFrustum& fr) const noexcept
{
    // Load origin and orientation of frustum B.
    XMVECTOR OriginB = XMLoadFloat3(&Origin);
    XMVECTOR OrientationB = XMLoadFloat4(&Orientation);

    assert(DirectX::Internal::XMQuaternionIsUnit(OrientationB));

    // Build the planes of frustum B.
    XMVECTOR AxisB[6];
    AxisB[0] = XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f);
    AxisB[1] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
    AxisB[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f);
    AxisB[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f);
    AxisB[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f);
    AxisB[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f);

    XMVECTOR PlaneDistB[6];
    PlaneDistB[0] = XMVectorNegate(XMVectorReplicatePtr(&Near));
    PlaneDistB[1] = XMVectorReplicatePtr(&Far);
    PlaneDistB[2] = XMVectorZero();
    PlaneDistB[3] = XMVectorZero();
    PlaneDistB[4] = XMVectorZero();
    PlaneDistB[5] = XMVectorZero();

    // Load origin and orientation of frustum A.
    XMVECTOR OriginA = XMLoadFloat3(&fr.Origin);
    XMVECTOR OrientationA = XMLoadFloat4(&fr.Orientation);

    assert(DirectX::Internal::XMQuaternionIsUnit(OrientationA));

    // Transform frustum A into the space of the frustum B in order to
    // minimize the number of transforms we have to do.
    OriginA = XMVector3InverseRotate(XMVectorSubtract(OriginA, OriginB), OrientationB);
    OrientationA = XMQuaternionMultiply(OrientationA, XMQuaternionConjugate(OrientationB));

    // Build the corners of frustum A (in the local space of B).
    XMVECTOR RightTopA = XMVectorSet(fr.RightSlope, fr.TopSlope, 1.0f, 0.0f);
    XMVECTOR RightBottomA = XMVectorSet(fr.RightSlope, fr.BottomSlope, 1.0f, 0.0f);
    XMVECTOR LeftTopA = XMVectorSet(fr.LeftSlope, fr.TopSlope, 1.0f, 0.0f);
    XMVECTOR LeftBottomA = XMVectorSet(fr.LeftSlope, fr.BottomSlope, 1.0f, 0.0f);
    XMVECTOR NearA = XMVectorReplicatePtr(&fr.Near);
    XMVECTOR FarA = XMVectorReplicatePtr(&fr.Far);

    RightTopA = XMVector3Rotate(RightTopA, OrientationA);
    RightBottomA = XMVector3Rotate(RightBottomA, OrientationA);
    LeftTopA = XMVector3Rotate(LeftTopA, OrientationA);
    LeftBottomA = XMVector3Rotate(LeftBottomA, OrientationA);

    XMVECTOR CornersA[CORNER_COUNT];
    CornersA[0] = XMVectorMultiplyAdd(RightTopA, NearA, OriginA);
    CornersA[1] = XMVectorMultiplyAdd(RightBottomA, NearA, OriginA);
    CornersA[2] = XMVectorMultiplyAdd(LeftTopA, NearA, OriginA);
    CornersA[3] = XMVectorMultiplyAdd(LeftBottomA, NearA, OriginA);
    CornersA[4] = XMVectorMultiplyAdd(RightTopA, FarA, OriginA);
    CornersA[5] = XMVectorMultiplyAdd(RightBottomA, FarA, OriginA);
    CornersA[6] = XMVectorMultiplyAdd(LeftTopA, FarA, OriginA);
    CornersA[7] = XMVectorMultiplyAdd(LeftBottomA, FarA, OriginA);

    // Check frustum A against each plane of frustum B.
    XMVECTOR Outside = XMVectorFalseInt();
    XMVECTOR InsideAll = XMVectorTrueInt();

    for (size_t i = 0; i < 6; ++i)
    {
        // Find the min/max projection of the frustum onto the plane normal.
        XMVECTOR Min, Max;

        Min = Max = XMVector3Dot(AxisB[i], CornersA[0]);

        for (size_t j = 1; j < CORNER_COUNT; j++)
        {
            XMVECTOR Temp = XMVector3Dot(AxisB[i], CornersA[j]);
            Min = XMVectorMin(Min, Temp);
            Max = XMVectorMax(Max, Temp);
        }

        // Outside the plane?
        Outside = XMVectorOrInt(Outside, XMVectorGreater(Min, PlaneDistB[i]));

        // Fully inside the plane?
        InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(Max, PlaneDistB[i]));
    }

    // If the frustum A is outside any of the planes of frustum B it is outside.
    if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
        return false;

    // If frustum A is inside all planes of frustum B it is fully inside.
    if (XMVector4EqualInt(InsideAll, XMVectorTrueInt()))
        return true;

    // Build the corners of frustum B.
    XMVECTOR RightTopB = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f);
    XMVECTOR RightBottomB = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f);
    XMVECTOR LeftTopB = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f);
    XMVECTOR LeftBottomB = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f);
    XMVECTOR NearB = XMVectorReplicatePtr(&Near);
    XMVECTOR FarB = XMVectorReplicatePtr(&Far);

    XMVECTOR CornersB[BoundingFrustum::CORNER_COUNT];
    CornersB[0] = XMVectorMultiply(RightTopB, NearB);
    CornersB[1] = XMVectorMultiply(RightBottomB, NearB);
    CornersB[2] = XMVectorMultiply(LeftTopB, NearB);
    CornersB[3] = XMVectorMultiply(LeftBottomB, NearB);
    CornersB[4] = XMVectorMultiply(RightTopB, FarB);
    CornersB[5] = XMVectorMultiply(RightBottomB, FarB);
    CornersB[6] = XMVectorMultiply(LeftTopB, FarB);
    CornersB[7] = XMVectorMultiply(LeftBottomB, FarB);

    // Build the planes of frustum A (in the local space of B).
    XMVECTOR AxisA[6];
    XMVECTOR PlaneDistA[6];

    AxisA[0] = XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f);
    AxisA[1] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
    AxisA[2] = XMVectorSet(1.0f, 0.0f, -fr.RightSlope, 0.0f);
    AxisA[3] = XMVectorSet(-1.0f, 0.0f, fr.LeftSlope, 0.0f);
    AxisA[4] = XMVectorSet(0.0f, 1.0f, -fr.TopSlope, 0.0f);
    AxisA[5] = XMVectorSet(0.0f, -1.0f, fr.BottomSlope, 0.0f);

    AxisA[0] = XMVector3Rotate(AxisA[0], OrientationA);
    AxisA[1] = XMVectorNegate(AxisA[0]);
    AxisA[2] = XMVector3Rotate(AxisA[2], OrientationA);
    AxisA[3] = XMVector3Rotate(AxisA[3], OrientationA);
    AxisA[4] = XMVector3Rotate(AxisA[4], OrientationA);
    AxisA[5] = XMVector3Rotate(AxisA[5], OrientationA);

    PlaneDistA[0] = XMVector3Dot(AxisA[0], CornersA[0]);  // Re-use corner on near plane.
    PlaneDistA[1] = XMVector3Dot(AxisA[1], CornersA[4]);  // Re-use corner on far plane.
    PlaneDistA[2] = XMVector3Dot(AxisA[2], OriginA);
    PlaneDistA[3] = XMVector3Dot(AxisA[3], OriginA);
    PlaneDistA[4] = XMVector3Dot(AxisA[4], OriginA);
    PlaneDistA[5] = XMVector3Dot(AxisA[5], OriginA);

    // Check each axis of frustum A for a seperating plane (5).
    for (size_t i = 0; i < 6; ++i)
    {
        // Find the minimum projection of the frustum onto the plane normal.
        XMVECTOR Min;

        Min = XMVector3Dot(AxisA[i], CornersB[0]);

        for (size_t j = 1; j < CORNER_COUNT; j++)
        {
            XMVECTOR Temp = XMVector3Dot(AxisA[i], CornersB[j]);
            Min = XMVectorMin(Min, Temp);
        }

        // Outside the plane?
        Outside = XMVectorOrInt(Outside, XMVectorGreater(Min, PlaneDistA[i]));
    }

    // If the frustum B is outside any of the planes of frustum A it is outside.
    if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
        return false;

    // Check edge/edge axes (6 * 6).
    XMVECTOR FrustumEdgeAxisA[6];
    FrustumEdgeAxisA[0] = RightTopA;
    FrustumEdgeAxisA[1] = RightBottomA;
    FrustumEdgeAxisA[2] = LeftTopA;
    FrustumEdgeAxisA[3] = LeftBottomA;
    FrustumEdgeAxisA[4] = XMVectorSubtract(RightTopA, LeftTopA);
    FrustumEdgeAxisA[5] = XMVectorSubtract(LeftBottomA, LeftTopA);

    XMVECTOR FrustumEdgeAxisB[6];
    FrustumEdgeAxisB[0] = RightTopB;
    FrustumEdgeAxisB[1] = RightBottomB;
    FrustumEdgeAxisB[2] = LeftTopB;
    FrustumEdgeAxisB[3] = LeftBottomB;
    FrustumEdgeAxisB[4] = XMVectorSubtract(RightTopB, LeftTopB);
    FrustumEdgeAxisB[5] = XMVectorSubtract(LeftBottomB, LeftTopB);

    for (size_t i = 0; i < 6; ++i)
    {
        for (size_t j = 0; j < 6; j++)
        {
            // Compute the axis we are going to test.
            XMVECTOR Axis = XMVector3Cross(FrustumEdgeAxisA[i], FrustumEdgeAxisB[j]);

            // Find the min/max values of the projection of both frustums onto the axis.
            XMVECTOR MinA, MaxA;
            XMVECTOR MinB, MaxB;

            MinA = MaxA = XMVector3Dot(Axis, CornersA[0]);
            MinB = MaxB = XMVector3Dot(Axis, CornersB[0]);

            for (size_t k = 1; k < CORNER_COUNT; k++)
            {
                XMVECTOR TempA = XMVector3Dot(Axis, CornersA[k]);
                MinA = XMVectorMin(MinA, TempA);
                MaxA = XMVectorMax(MaxA, TempA);

                XMVECTOR TempB = XMVector3Dot(Axis, CornersB[k]);
                MinB = XMVectorMin(MinB, TempB);
                MaxB = XMVectorMax(MaxB, TempB);
            }

            // if (MinA > MaxB || MinB > MaxA) reject
            Outside = XMVectorOrInt(Outside, XMVectorGreater(MinA, MaxB));
            Outside = XMVectorOrInt(Outside, XMVectorGreater(MinB, MaxA));
        }
    }

    // If there is a seperating plane, then the frustums do not intersect.
    if (XMVector4EqualInt(Outside, XMVectorTrueInt()))
        return false;

    // If we did not find a separating plane then the frustums intersect.
    return true;
}