FHeightfieldRaycastVisitor::VisitSweep skips the painted-hole (visibility
mask) check when the swept sphere starts in initial overlap with a
heightfield cell, producing a spurious zero-distance hit on invisible
terrain.
See repro description.
Root cause
----------
GeometryQueries.h SweepQuery routes (Sphere, bComputeMTD=false) through
FHeightField::Raycast, which with Thickness>0 uses
FHeightfieldRaycastVisitor::VisitSweep (HeightField.cpp ~line 110).
That visitor has two hit branches. The “border” branch at ~line 217-237
filters cells via:
bHole = GeomData->MaterialIndices[CellIndex] == TNumericLimits<uint8>::Max();
if (!bHole) { …store hit… }
The earlier “initial overlap” branch at ~line 145-157 returns the hit
without consulting MaterialIndices:
if (Time == 0)
{
const FVec3 ClosestPtOnTri \= FindClosestPointOnTriangle(...);
if (DistToTriangle2 \<\= Radius2\)
{
OutTime \= 0;
...
return true; // \<\- hole check missing
}
}
So a sphere already overlapping a hole cell at t=0 bypasses the filter.
Suggested fix
-------------
Mirror the existing hole test in the initial-overlap branch:
if (DistToTriangle2 <= Radius2)
{
const int32 CellIndex \= FaceIndex / 2;
if (GeomData\-\>MaterialIndices.IsValidIndex(CellIndex)
\&\& GeomData\-\>MaterialIndices\[CellIndex] \=\= TNumericLimits\<uint8\>::Max())
{
return false;
}
OutTime \= 0;
...
return true;
}
[Attachment Removed]