I’m writing a world partition builder that goes through the world and in our main world where the physics is complex, each call to LineTraceSingleByChannel takes around 5ms compared to normal runtime or editor use where it’s less than 0.1ms.
I enable trace collision in the world initialization values.
UWorld::InitializationValues UProcessDataWorldPartitionBuilder::GetWorldInitializationValues() const
{
UWorld::InitializationValues IVS = Super::GetWorldInitializationValues();
IVS.EnableTraceCollision( true );
return IVS;
}
It’s slow because it takes a different route in the AABBTree, on line 2955 “if (DirtyElements.Num() > 0)” is true which is different from how it is normally (when it’s fast).
Somehow some physics acceleration structure isn’t built, so my calls are very slow. I’m not sure how to ensure they are built.
in “RunInternal” I’ve tried adding
FStaticMeshCompilingManager::Get().FinishAllCompilation();
FWorldPartitionHelpers::FakeEngineTick( _world );
World->GetPhysicsScene()->Flush();
to ensure that all the meshes are compiled and the physics structure is ready, but it doesn’t work. There is something I’m missing, but I don’t know what.
Thanks in advance.
slow_trace.png(330 KB)
Hi Joel,
From the description, you’ve got a good amount of the way there yourself. The DirtyElements array holds objects which haven’t made it into our spatial partitioning structure yet, and need to be searched linearly - as you called out, this is almost certainly the reason for the slowdown.
I’m not 100% certain what is causing this - but again from context it sounds like the physics engine is getting overloaded or there is a variable there which is limiting the time chaos can spend updating the spatial acceleration structure (which is how the dirty elements get removed from the list and find their way into the AABB tree). This can be a common situation when there is a lot of geometry loaded at once, and the physics has a lot of work which needs to be done in order to build a huge AABB tree.
There are a lot of CVars in AABBTree.cpp which can affect this process, so I’d check there and see if it is different from the default settings. I’d also try and add a delay between loading and starting raycasting. Finally you can add some debug output into Reset and GenerateTree (in AABBTree.h) which would allow you to see if there is a reason why the dirty list isn’t getting cleared as often as expected.
All the best
Geoff Stacey
Developer Relations
EPIC Games
Great stuff Joel, and thank you for updating this - I’m sure anyone reading this will be sending you good vibes 
Best
Geoff
I removed my initial reply with my solution due the commandlet not working as expected. Now it’s confirmed to be working, so I’m returning with what I did in the end in case it helps someone else.
bool UMyWorldPartitionBuilder::PreRun( UWorld* World, FPackageSourceControlHelper& PackageHelper )
{
...
UKismetSystemLibrary::ExecuteConsoleCommand( World, "p.aabbtree.DirtyElementMaxCellCapacity 100000", nullptr );
...
}
bool UMyWorldPartitionBuilder::RunInternal( UWorld* World, const FCellInfo& InCellInfo, FPackageSourceControlHelper& PackageHelper )
{
...
// Iterating on the minimum permutation of these calls is slow for me, so I haven't done it yet. This works for us...
FStaticMeshCompilingManager::Get().FinishAllCompilation();
for ( int i = 0; i < 10; ++i )
{
FWorldPartitionHelpers::FakeEngineTick( World );
}
World->GetPhysicsScene()->Flush();
World->GetPhysicsScene()->Flush();
World->GetPhysicsScene()->Flush();
for ( int i = 0; i < 10; ++i )
{
FWorldPartitionHelpers::FakeEngineTick( World );
}
...
// Perform line traces here
}