I’m generating terrain using the procedural mesh component at runtime. There is a noticeable stutter when generating new chunks of terrain that I would like to resolve. I’ve tried calling UProceduralMeshComponent::CreateMeshSection in an AsyncTask on FNamedThreads::Type::AnyThread but it crashes. Is the UProceduralMeshComponent thread safe? Is there any way to have the mesh generated asynchronously to avoid a stutter?
3 Likes
I was able to create the procedural mesh component on a separate thread and then call CreateMeshSection on that thread before registering and attaching the component to the actor on the game thread. This seems to work, although, occasionally I get a crash in GC if I stop the game before the mesh has been completely generated. I needed to remove the Async flags of the procedural mesh component and its ProcMeshBody setup for garbage collection.
AsyncTask(ENamedThreads::AnyThread, [this]()
{
bGenerating = true;
Mesh = NewObject<UProceduralMeshComponent>(this, UProceduralMeshComponent::StaticClass());
Mesh->ClearInternalFlags(EInternalObjectFlags::Async); /* Called to allow garbage collection visit: https://georgy.dev/posts/avoid-gc-async/ for details */
CreateVertices();
CreateTriangles();
TArray<FColor> VertexColors;
bool bCreateCollision = true;
UKismetProceduralMeshLibrary::CalculateTangentsForMesh(Vertices, Triangles, RenderUVs, Normals, Tangents);
Mesh->CreateMeshSection(0, Vertices, RenderTriangles, Normals, RenderUVs, VertexColors, Tangents, bCreateCollision);
Mesh->ProcMeshBodySetup.Get()->ClearInternalFlags(EInternalObjectFlags::Async);
AsyncTask(ENamedThreads::GameThread, [this]()
{
if (Mesh.IsValid())
{
Mesh->RegisterComponent();
Mesh->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetIncludingScale);
Mesh->SetMaterial(0, Material);
}
});
bGenerating = false;
});
3 Likes