Description

Geometry Collection (GC) fragments are affecting the Navmesh in wrong positions and the identified cause is wrong indexing. Once a GC breaks, it's fragments, when big enough, are creating islands in the Navmesh that do not coincide with their actual positioning in the world.
The licensee has tracked the issue to \UnrealEngine\Engine\Source\Runtime\Experimental\GeometryCollectionEngine\Private\GeometryCollection\GeometryCollectionComponent.cpp, UGeometryCollectionComponent::DoCustomNavigableGeometryExport, inside a ParallelFor:
const FVector3f VertexInComponentSpace = GeomToComponent[SubsetIndex].TransformPosition(Vertex[SourceGeometryVertexIndex]);
It should be:
const FVector3f VertexInComponentSpace = GeomToComponent[GeometryIndex].TransformPosition(Vertex[SourceGeometryVertexIndex]);
The function is using the index from a filtered/subset array (GeometryIndexBuffer) to access the transform in the unfiltered array (GeomToComponent).
Using GeometryIndex (the index of the unfiltered array GeomToComponent) instead of SubsetIndex (the filtered/subset index of GeometryIndexBuffer), along with the required fixes in the code, apparently fixed the issue.
Please refer to the licensee's repro project as it is a very elaborate test case. It requires an engine modification to run, and it can be applied by following these instructions:
Steps to Reproduce
Sync unreal 5.5.0 / 1308e62273a620dd4584b830f6b32cd8200c2ad3
Apply provided .patch to engine (cmd> git apply UnrealEngine-ec5b2a4-GC-Navmesh_Holes.patch)
Unzip / compile / run the provided project: FPS_55_Repro

Select the actor GC_SM_ChamferCube6 then its geometry collection component, scroll down to "NAV DEBUG" section of its properties
Ensure "Use Fix" is false, "Filter Out Even Indexes" is true
Run the game, wait for the cube in front of the starting position to shatter, click on "RefreshIndices" in the GC properties, then observe the navmesh (walk on fragments until the navmesh turns red then green again if it doesn't refresh by itself): some even numbered fragment generate holes in the navmesh (they shouldn't) and some holes seems to not properly match the shape of the fragment
Stop the game, in GC_SM_ChamferCube6 geometry collection component set "Use Fix" to true, "Filter Out Even Indexes" remains true too
Restart the game, show indices once the cube is shattered and observe the navmesh: as expected even numbered fragments generate no hole, off numbered fragment generate a hole in the navmesh matching their shape

Steps to Reproduce

The licensee has provided an elaborate repro case that shows the issue with great detail and requires an engine modification to compare the corrected code with the faulty one.
To reproduce the issue:
Create a Geometry Collection (GC) big enough that its fragments affect the Navmesh (2-3x bigger than the standard cube)
Add a Navmesh in the level
Add a MasterField overlapping with the GC and configure its forces so that it breaks the GC and randomly distribute the fragments (suggest using FS_MasterField or FS_BombField)
Press P to show navigation
Simulate the scene and check that the Navmesh is affect by the fragments, but the position does not coincide with the actual fragments positioning - it's easier to see using the licensee's elaborate test, or if the fragments are very far apart Please refer to the attached images.
Expected behavior: the navmesh would be affected where the fragments are located
Actual behavior: the navmesh is affected in somewhat random locations

Callstack

> UnrealEditor-GeometryCollectionEngine.dll!UGeometryCollectionComponent::DoCustomNavigableGeometryExport::__l66::<lambda_1>::operator()(int PointIdx) Line 1537 C++
[Inline Frame] UnrealEditor-GeometryCollectionEngine.dll!UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::FFunctionRefStoragePolicy,void __cdecl(int)>::operator()(int <Params_0>) Line 470 C++
[Inline Frame] UnrealEditor-GeometryCollectionEngine.dll!ParallelForImpl::CallBody(const TFunctionRef<void __cdecl(int)> &) Line 80 C++
UnrealEditor-GeometryCollectionEngine.dll!`ParallelForImpl::ParallelForInternal<TFunctionRef<void __cdecl(int)>,`ParallelFor'::`2'::<lambda_1>,std::nullptr_t>'::`2'::FParallelExecutor::operator()(const bool bIsMaster) Line 116 C++
[Inline Frame] UnrealEditor-GeometryCollectionEngine.dll!LowLevelTasks::FTask::Init::__l13::<lambda_1>::operator()(const bool) Line 499 C++
[Inline Frame] UnrealEditor-GeometryCollectionEngine.dll!Invoke(LowLevelTasks::FTask::Init::__l13::<lambda_1> &) Line 47 C++
[Inline Frame] UnrealEditor-GeometryCollectionEngine.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`ParallelForImpl::ParallelForInternal<TFunctionRef<void __cdecl(int)>,`ParallelFor'::`2'::<lambda_1>,std::nullptr_t>'::`2'::FParallelExecutor>'::`13'::<lambda_1>,0>::Call(void *) Line 162 C++
UnrealEditor-GeometryCollectionEngine.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`ParallelForImpl::ParallelForInternal<TFunctionRef<void __cdecl(int)>,`ParallelFor'::`2'::<lambda_1>,std::nullptr_t>'::`2'::FParallelExecutor>'::`13'::<lambda_1>,0>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> & Destination, void * InlineData, unsigned int DestInlineSize, bool <Params_0>) Line 171 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &) Line 308 C++
UnrealEditor-Core.dll!LowLevelTasks::FTask::ExecuteTask() Line 627 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::ExecuteTask(LowLevelTasks::FTask * InTask) Line 245 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::FScheduler::TryExecuteTaskFrom(LowLevelTasks::Private::FWaitEvent *) Line 457 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::WorkerLoop(LowLevelTasks::Private::FWaitEvent * WorkerEvent, LowLevelTasks::Private::TLocalQueueRegistry<1024,1024>::TLocalQueue * WorkerLocalQueue, unsigned int WaitCycles, bool bPermitBackgroundWork) Line 514 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::FScheduler::WorkerMain(LowLevelTasks::Private::FWaitEvent * WorkerEvent, LowLevelTasks::Private::TLocalQueueRegistry<1024,1024>::TLocalQueue * WorkerLocalQueue, unsigned int WaitCycles, bool bPermitBackgroundWork) Line 571 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::CreateWorker::__l2::<lambda>() Line 75 C++
[Inline Frame] UnrealEditor-Core.dll!UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(void)>::operator()() Line 470 C++
UnrealEditor-Core.dll!FThreadImpl::Run() Line 69 C++
UnrealEditor-Core.dll!FRunnableThreadWin::Run() Line 159 C++
UnrealEditor-Core.dll!FRunnableThreadWin::GuardedRun() Line 71 C++
[External Code]

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-232436 in the post.

0
Login to Vote

Unresolved
CreatedDec 6, 2024
UpdatedDec 20, 2024
View Jira Issue