Replacing Procedural Mesh Component Sections Removes other sections

I’m using procedural mesh component for terrain that can be modified at run time. The component has 16 mesh sections so that processing the terrain changes can be done in parallel.
This is the code I’m using to make updates:

TerrainMesh->ClearMeshSection(SectionID);

TerrainMesh->CreateMeshSection(SectionID, VertexLocations, VertexIndices, VertexNormals, VertexUVs, VertexColors, VertexTangents, true);

Clearing and replacing an index removes every index after the index your replacing. For example clearing and replacing index 5 removes indexes 6-15, indexes 4 and below are unaffected. According to the documentation clear mesh does not alter the indexes of other sections.

I use clear and create because the world is sliced into layers and when changes (terrain raised or lowered) are made vertices may be removed or added to the layer.

Hi chrisrf,

Does this occur in a clean, blank project with no additional content or is it limited to one project? Is this a c++ or blueprint project? What steps can I take it to reproduce this on my end?

I haven’t tried doing this in a clean project yet and the project I’m using was originally 4.8 (which also had the issue) and upgraded to 4.9. I started the project as the 3rd person blueprint template and I originally had all my procedural mesh code in blueprints (which also had the issue) but I’ve ported everything over so everything is done in c++ now.

Can you show me the code for the procedural component sections? Additionally, can you show me what your blueprint event graph had in it so I can try to reproduce this on my end?

I’m not doing anything in BPs anymore, its all c++ but here’s my code. I’ve tried to get this formatted better but it doesn’t seem to want to cooperate.

struct FLayerData
{
FLayerData(const int32 LayerNumber, const int32 SectionNumber)
{
Layer = LayerNumber;
SectionID = SectionNumber;
};

int32 Layer;
int32 SectionID;

TArray<FVector> VertexLocations;
TArray<int32> VertexIndices;
TArray<FVector> VertexNormals;
TArray<FVector2D> VertexUVs;
TArray<FColor> VertexColors;
TArray<FProcMeshTangent> VertexTangents;

};

void AVoxelWorld::Tick(float DeltaSeconds)
{
if (processing_threads) {
bool AllDone = true;
for (int32 i = 0; i < MeshUpdates.Num(); i++) {
if (MeshUpdates[i]->IsRunning()) {
AllDone = false;
break;
}
}

	if (AllDone) {
		for (int32 i = 0; i < MeshUpdates.Num(); i++) {
			TerrainThread* update = MeshUpdates[i];

			WorldLayers[update->GetLayer()]->AddLayerDataToMesh(update->GetTerrainData(), update->GetFloorData(), ActiveLayer);
			delete update;
		}

		MeshUpdates.Empty();
		processing_threads = false;
		LayerMutex.unlock();
	}
}

}

void AWorldLayer::AddLayerDataToMesh(const FLayerData* const terrain, const FLayerData* const floor, const int32 ActiveLayer)
{
TerrainMesh->ClearMeshSection(terrain->SectionID);
//FloorMesh->ClearMeshSection(terrain->SectionID);

TerrainMesh->CreateMeshSection(terrain->SectionID, terrain->VertexLocations, terrain->VertexIndices, terrain->VertexNormals, terrain->VertexUVs, terrain->VertexColors, terrain->VertexTangents, true);
//FloorMesh->CreateMeshSection(floor->SectionID, floor->VertexLocations, floor->VertexIndices, floor->VertexNormals, floor->VertexUVs, floor->VertexColors, floor->VertexTangents, true);

}

Have you tried adding breakpoints to see where the clear is occurring? Specifically, try adding a breakpoint after the line TerrainMesh->ClearMeshSection() and see if the error occurs after this line.

How do you debug plugins? I can’t see whats going on inside the component.

Hey chrisrf-

Inside the Plugins folder of the project directory the plugin should have its own .sln file that you can open and check the code on.

I don’t see an .sln file in either the ProceduralMeshComponent folder of the engine, the plugins folder, or any plugin folder in my game’s directory. I don’t see any .sln files for the engine at all, just .uplugin files.

I Dug through the UProceduralMeshComponent code and I saw this:

void UProceduralMeshComponent::CreateMeshSection(int32 SectionIndex, …)
{

// Ensure sections array is long enough
ProcMeshSections.SetNum(SectionIndex + 1, false);

    ...

}

ProcMeshSections is declared in the header as it is below:
TArray< FProcMeshSection > ProcMeshSections;

This looked suspicious so I did some testing on my own. It turns out that even if you set bAllowShrinking to false (as the code above shows) TArray still shortens the array down to the specified index if its smaller than the existing size when you call SetNum(). I don’t know what exactly is going on in the internals and it may not be that the array itself is being re-sized but the int32 counter keeping track of the number of indices inside TArray is definitely being changed.