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