inline bool XM_CALLCONV BoundingFrustum::Intersects()

in Inc/DirectXCollision.inl [3993:4086]


inline bool XM_CALLCONV BoundingFrustum::Intersects(FXMVECTOR rayOrigin, FXMVECTOR Direction, float& Dist) const noexcept
{
    // If ray starts inside the frustum, return a distance of 0 for the hit
    if (Contains(rayOrigin) == CONTAINS)
    {
        Dist = 0.0f;
        return true;
    }

    // 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);

    // Load origin and orientation of the frustum.
    XMVECTOR frOrigin = XMLoadFloat3(&Origin);
    XMVECTOR frOrientation = XMLoadFloat4(&Orientation);

    // This algorithm based on "Fast Ray-Convex Polyhedron Intersectin," in James Arvo, ed., Graphics Gems II pp. 247-250
    float tnear = -FLT_MAX;
    float tfar = FLT_MAX;

    for (size_t i = 0; i < 6; ++i)
    {
        XMVECTOR Plane = DirectX::Internal::XMPlaneTransform(Planes[i], frOrientation, frOrigin);
        Plane = XMPlaneNormalize(Plane);

        XMVECTOR AxisDotOrigin = XMPlaneDotCoord(Plane, rayOrigin);
        XMVECTOR AxisDotDirection = XMVector3Dot(Plane, Direction);

        if (XMVector3LessOrEqual(XMVectorAbs(AxisDotDirection), g_RayEpsilon))
        {
            // Ray is parallel to plane - check if ray origin is inside plane's
            if (XMVector3Greater(AxisDotOrigin, g_XMZero))
            {
                // Ray origin is outside half-space.
                Dist = 0.f;
                return false;
            }
        }
        else
        {
            // Ray not parallel - get distance to plane.
            float vd = XMVectorGetX(AxisDotDirection);
            float vn = XMVectorGetX(AxisDotOrigin);
            float t = -vn / vd;
            if (vd < 0.0f)
            {
                // Front face - T is a near point.
                if (t > tfar)
                {
                    Dist = 0.f;
                    return false;
                }
                if (t > tnear)
                {
                    // Hit near face.
                    tnear = t;
                }
            }
            else
            {
                // back face - T is far point.
                if (t < tnear)
                {
                    Dist = 0.f;
                    return false;
                }
                if (t < tfar)
                {
                    // Hit far face.
                    tfar = t;
                }
            }
        }
    }

    // Survived all tests.
    // Note: if ray originates on polyhedron, may want to change 0.0f to some
    // epsilon to avoid intersecting the originating face.
    float distance = (tnear >= 0.0f) ? tnear : tfar;
    if (distance >= 0.0f)
    {
        Dist = distance;
        return true;
    }

    Dist = 0.f;
    return false;
}