DynamicMeshComponent is slower then ProceduralMeshComponent?

I am changing my procedural terrain system to use DynamicMeshComponent instead of ProceduralMeshComponent, but i’ve notices slower results. I’ve heard alot of people say that DMC is better then PMC, so I think I’m doing something wrong.
I currently have a dummy class to test both DMC and PMC.

void ADynamicTerrain::CreateMeshSection_Dynamic(int32 Size, UMaterialInstance* Material, bool Collisions)
{
	FDynamicMesh3 MeshInfo;
	MeshInfo.EnableAttributes();
	MeshInfo.EnableVertexUVs(FVector2f::Zero());

	for (int32 x = 0; x <= Size; x++)
	{
		for (int32 y = 0; y <= Size; y++)
		{
			const int32 VertexID = MeshInfo.AppendVertex(FVector3d(x * 100, y * 100, 0));
			MeshInfo.SetVertexUV(VertexID, FVector2f(x,y));
		}
	}

	for (int32 x = 0; x < Size; x++)
	{
		for (int32 y = 0; y < Size; y++)
		{
			int32 topLeft = x * (Size + 1) + y;
			int32 topRight = topLeft + 1;
			int32 bottomLeft = (x + 1) * (Size + 1) + y;
			int32 bottomRight = bottomLeft + 1;

			MeshInfo.AppendTriangle(topLeft, topRight, bottomLeft);
			MeshInfo.AppendTriangle(bottomLeft, topRight, bottomRight);
		}
	}
	UE::Geometry::FMeshNormals::QuickComputeVertexNormals(MeshInfo);
	CopyVertexUVsToOverlay(MeshInfo, *MeshInfo.Attributes()->PrimaryUV());

	//Create mesh

	UDynamicMeshComponent* MeshComponent = NewObject<UDynamicMeshComponent>(this);
	MeshComponent->RegisterComponent();
	MeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
	MeshComponent->CastShadow = false;

	MeshComponent->SetMesh(MoveTemp(MeshInfo));
	MeshComponent->SetMaterial(0, Material);
	
	if (Collisions)
	{
		MeshComponent->bUseAsyncCooking = true;
		MeshComponent->BodyInstance.SetCollisionProfileName("BlockAll");
		MeshComponent->EnableComplexAsSimpleCollision();
	}
}

Here is PMC :

void ADynamicTerrain::CreateMeshSection_Procedural(int32 Size, UMaterialInstance* Material, bool Collisions)
{

	TArray<FVector> Vertices;
	TArray<int32> Triangles;
	TArray<FVector> Normals;
	TArray<FVector2D> UV0;

	for (int32 x = 0; x <= Size; x++)
	{
		for (int32 y = 0; y <= Size; y++)
		{
			Vertices.Add(FVector(x * 100, y * 100, 0));
			UV0.Add(FVector2D(x,y));
		}
	}
	for (int32 x = 0; x < Size; x++)
	{
		for (int32 y = 0; y < Size; y++)
		{
			int32 topLeft = x * (Size + 1) + y;
			int32 topRight = topLeft + 1;
			int32 bottomLeft = (x + 1) * (Size + 1) + y;
			int32 bottomRight = bottomLeft + 1;
			
			Triangles.Add(topLeft);
			Triangles.Add(topRight);
			Triangles.Add(bottomLeft);
			Triangles.Add(bottomLeft);
			Triangles.Add(topRight);
			Triangles.Add(bottomRight);
		}
	}

	CalculateFastNormals(Normals);
	
	
	UProceduralMeshComponent* MeshComponent = NewObject<UProceduralMeshComponent>(this);
	MeshComponent->RegisterComponent();
	MeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
	MeshComponent->CastShadow = false;
	MeshComponent->bUseAsyncCooking = true;

	
	MeshComponent->CreateMeshSection(0, Vertices, Triangles, Normals, UV0, TArray<FColor>(), TArray<FProcMeshTangent>(), Collisions);
	MeshComponent->SetMaterial(0, Material);
}

I have made these as similiar as possible, yet could not get the performance of PMC using DMC. PMC (with collisions, normals and uv’s) is still faster then DMC (without collisions, normals and uv’s).

Interesting information. I wanted to use DynamicMeshComponent instead of ProceduralMeshComponent.
In UE there is also a class UOctreeDynamicMeshComponent.
Maybe it will be faster.

FDynamicMesh3 is not UCLASS and maybe you can use asynchronous queries to it and it will be faster.
Perhaps FDynamicMesh3 creates additional features. ProceduralMeshComponent does not support decals, maybe FDynamicMesh3 solved this problem.

1 Like

Yea, probably due to extra overhead. I’m trying to find a way to update only certain vertices in DynamicMeshComponent, but can’t find a solution.

Example of changing vertexes:

UDynamicMesh* DynMesh2 = DynamicMeshComponent->GetDynamicMesh();
FVector Translation(150, 150, 150);

DynMesh2->EditMesh([&](FDynamicMesh3& EditMesh)
	{		
		int NumVertices = EditMesh.MaxVertexID();
		ParallelFor(NumVertices, [&](int vid)
			{
				if (EditMesh.IsVertex(vid))
				{
					EditMesh.SetVertex(vid, EditMesh.GetVertex(vid) + Translation);
				}
			});
	}, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::VertexPositions, false);

It’s better to use:

UDynamicMesh* DynMesh3 = DynamicMeshComponent->GetDynamicMesh();
DynMesh3->SetMesh(DynMesh2);

instead

MeshComponent->SetMesh(MoveTemp(MeshInfo));

So, I’d initialize a UDynamicMesh* on the game thread

UDynamicMesh* DynamicMesh = DynamicMeshComponent->GetDynamicMesh();

Then, on an async thread, creating vertices, triangles, UV’s, Normals and Tangents on putting them in the FDynamicMesh3.
Could I also call this function on said async thread?

DynamicMesh->SetMesh(Mesh);

After than, on the game thread, I would Modify the location on this component, set material and enable collisions.

DynamicMeshComponent->SetRelativeTransform(
		FTransform(FRotator::ZeroRotator,
		FVector(Offset.X * Scale, Offset.Y * Scale, MainActor->GetActorLocation().Y),
		FVector(1.0f, 1.0f, 1.0f)));
	
DynamicMeshComponent->SetMaterial(0, MainActor->TerrainInfo.Material);
if (Collision)
{
	DynamicMeshComponent->BodyInstance.SetCollisionProfileName("BlockAll");
	DynamicMeshComponent->EnableComplexAsSimpleCollision();
}

I found an option to edit individual vertexes without calling EditMesh().

#include "Util/DynamicVector.h"

UDynamicMesh* DynMesh2 = DynamicMeshComponent->GetDynamicMesh();
FDynamicMesh3* DynMesh3 = DynamicMeshComponent->GetMesh();

/* Прямое редактирование меша по ссылке на массив вертексов */
// Get vertexs by reference
UE::Geometry::TDynamicVector<FVector3d> Vert = DynMesh3->GetVerticesBuffer();
Vert[0] = FVector3d{ 0, 0, 222 };
Vert[1] = FVector3d{ 0, 0, 222 };
Vert[2] = FVector3d{ 0, 0, 222 };
DynMesh3->UpdateChangeStamps(true, false);		// update mesh

// or
// DynamicMeshComponent->FastNotifyPositionsUpdated();
1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.