inline bool XM_CALLCONV BoundingFrustum::Intersects()

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