Can't see cap material after slicing procedural mesh which is generated by code

Hello, everyone!

I was trying to copy player’s skeletal mesh and pose to procedural mesh at runtime, then slice the procedural mesh.

But I can’t find any provided method to achieve it. So I dig into MeshUtilities and KismetProceduralMeshLibrary to see if I can make a procedural mesh by getting data from skeletal mesh.

I made it, but the result looks a little different from the origin skeletal mesh.

And after slicing the procedural mesh, I can’t see the material on the cap.

I wondered what it should look like, so I made a static mesh in editor, copy it to procedural mesh and slice it.

I have no idea how to fix it. Is it because I use the data in a wrong way?

Thanks for help.

void ATestCharacter::CopyMesh() {
	ProcMeshComponent->SetWorldTransform(GetMesh()->GetComponentTransform());

	if (ProcMeshComponent != nullptr) {
		int32 InOverallMaxLODs = 0;
		InOverallMaxLODs = FMath::Max(GetMesh()->MeshObject->GetSkeletalMeshResource().LODModels.Num(), InOverallMaxLODs);
		GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, "InOverallMaxLODs : " + FString::FromInt(InOverallMaxLODs));
		int32 LODIndex = 0;
		FSkeletalMeshLODInfo& SrcLODInfo = GetMesh()->SkeletalMesh->LODInfo[LODIndex];

		// Get the CPU skinned verts for this LOD
		TArray<FFinalSkinVertex> FinalVertices;
		GetMesh()->GetCPUSkinnedVertices(FinalVertices, LODIndex);

		FSkeletalMeshResource& SkeletalMeshResource = GetMesh()->MeshObject->GetSkeletalMeshResource();
		FStaticLODModel& StaticLODModel = SkeletalMeshResource.LODModels[LODIndex];

		uint32 Max_Coords = 8;

		const uint32 NumTexCoords = FMath::Min(StaticLODModel.VertexBufferGPUSkin.GetNumTexCoords(), Max_Coords);
		const int32 NumSections = StaticLODModel.Sections.Num();
		FRawStaticIndexBuffer16or32Interface& IndexBuffer = *StaticLODModel.MultiSizeIndexContainer.GetIndexBuffer();

		GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, "NumSections : " + FString::FromInt(NumSections));

		//MyVertices as Vertices
		TArray<FVector> MyVertices;

		//WedgeIndices as Triangles?
		TArray<int32>MyTriangles;

		//WedgeTangetX as Tangent?
		TArray<FProcMeshTangent>MyTangent;

		//WedgeTangetZ as Normal?
		TArray<FVector>MyNormal;

		//WedgeTexCoords as UV?
		TArray<FVector2D> MyUV;

		TArray<FColor> Colors;

		// Map from vert buffer for whole mesh to vert buffer for section of interest
		TMap<int32, int32> MeshToSectionVertMap;

		FMatrix WorldToRoot = GetMesh()->GetComponentTransform().ToMatrixWithScale().Inverse();
		FMatrix ComponentToWorld = GetMesh()->GetComponentTransform().ToMatrixWithScale() * WorldToRoot;
		//FMatrix ComponentToWorld = GetMesh()->GetComponentTransform().ToMatrixWithScale();
		for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++) {
			const FSkelMeshSection& SkelMeshSection = StaticLODModel.Sections[SectionIndex];
			if (!SkelMeshSection.bDisabled) {
				// Build 'wedge' info
				const int32 NumWedges = SkelMeshSection.NumTriangles * 3;
				for (int32 WedgeIndex = 0; WedgeIndex < NumWedges; WedgeIndex++) {

					const int32 VertexIndexForWedge = IndexBuffer.Get(SkelMeshSection.BaseIndex + WedgeIndex);

					int32* NewIndexPtr = MeshToSectionVertMap.Find(VertexIndexForWedge);
					if (NewIndexPtr != nullptr) {
						//Copy Triangles
						MyTriangles.Add(*NewIndexPtr);
					}
					else {
						// Copy position
						int32 SectionVertIndex = MyVertices.Add(FinalVertices[VertexIndexForWedge].Position);

						const FFinalSkinVertex& SkinnedVertex = FinalVertices[VertexIndexForWedge];
						const FVector TangentX = ComponentToWorld.TransformVector(SkinnedVertex.TangentX);
						FProcMeshTangent NewTangent(TangentX, 0);

						// Copy tangents
						MyTangent.Add(NewTangent);
						// Copy normal
						const FVector TangentZ = ComponentToWorld.TransformVector(SkinnedVertex.TangentZ);
						MyNormal.Add(TangentZ);
						// Copy UVs
						MyUV.Add(StaticLODModel.VertexBufferGPUSkin.GetVertexUV(VertexIndexForWedge, 0));

						MeshToSectionVertMap.Add(VertexIndexForWedge, SectionVertIndex);

						//Copy Triangles
						MyTriangles.Add(SectionVertIndex);

						if (StaticLODModel.ColorVertexBuffer.IsInitialized())
						{
							Colors.Add(StaticLODModel.ColorVertexBuffer.VertexColor(VertexIndexForWedge));
							//RawMeshTracker.bValidColors = true;
						}
						else
						{
							Colors.Add(FColor::White);
						}
					}
				}
			}
			TArray<FLinearColor> DummyColors;
			ProcMeshComponent->CreateMeshSection_LinearColor(SectionIndex, MyVertices, MyTriangles, MyNormal, MyUV, DummyColors, MyTangent, false);
		}

		// Clear any existing collision hulls
		ProcMeshComponent->ClearCollisionConvexMeshes();
		ProcMeshComponent->AddCollisionConvexMesh(MyVertices);

		//// MATERIALS
		for (int32 MatIndex = 0; MatIndex < GetMesh()->GetNumMaterials(); MatIndex++)
		{
			ProcMeshComponent->SetMaterial(MatIndex, GetMesh()->GetMaterial(MatIndex));
		}
		ProcMeshComponent->SetSimulatePhysics(true);
		ProcMeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
	}
}

Problem resolved!
You have to reset every array when it comes to new section

MyVertices.Reset();
MyTriangles.Reset();
MyTangent.Reset();
MyNormal.Reset();
MyUV.Reset();