Create procedural mesh from animated skeletal mesh?

Is there a way to do this in C++?

I’ve found a couple of things that explain something similar but can’t quite work it out.

Basically I want to have a procedural mesh that is an exact copy of the skeletal mesh, including animations and morphs, and have it updating at runtime.

It should also have collision.

I don’t mind if this will be expensive, it will only be used for one or 2 meshes.

This should help, however it doesn’t work with morph targets.

void CopySkeletalMeshToProcedural(USkeletalMeshComponent* SkeletalMeshComponent, int32 LODIndex, UProceduralMeshComponent* ProcMeshComponent)
{

	FSkeletalMeshRenderData* SkMeshRenderData = SkeletalMeshComponent->GetSkeletalMeshRenderData();
	const FSkeletalMeshLODRenderData& DataArray = SkMeshRenderData->LODRenderData[LODIndex];
    FSkinWeightVertexBuffer& SkinWeights = *SkeletalMeshComponent->GetSkinWeightBuffer(LODIndex);

	TArray<FVector> VerticesArray;
	TArray<FVector> Normals;
	TArray<FVector2D> UV;
	TArray<int32> Tris;
	TArray<FColor> Colors;
	TArray<FProcMeshTangent> Tangents;

	
	//get num vertices
	int32 NumSourceVertices = DataArray.RenderSections[0].NumVertices;

	for (int32 i = 0; i < NumSourceVertices; i++)
	{
		//get skinned vector positions
		FVector SkinnedVectorPos = USkeletalMeshComponent::GetSkinnedVertexPosition(SkeletalMeshComponent, i, DataArray, SkinWeights);
		VerticesArray.Add(SkinnedVectorPos);

		//Calc normals and tangents from the static version instead of the skeletal one
		FVector ZTangentStatic = DataArray.StaticVertexBuffers.StaticMeshVertexBuffer.VertexTangentZ(i);
		FVector XTangentStatic = DataArray.StaticVertexBuffers.StaticMeshVertexBuffer.VertexTangentX(i);

		//add normals from the static mesh version instead because using the skeletal one doesn't work right.
		Normals.Add(ZTangentStatic);

		//add tangents
		Tangents.Add(FProcMeshTangent(XTangentStatic, false));

		//get UVs
		FVector2D uvs = DataArray.StaticVertexBuffers.StaticMeshVertexBuffer.GetVertexUV(i, 0);
		UV.Add(uvs);

		//dummy vertex colors
		Colors.Add(FColor(0, 0, 0, 255));
	}


	//get index buffer
	FMultiSizeIndexContainerData indicesData;
	DataArray.MultiSizeIndexContainer.GetIndexBuffer(indicesData.Indices);

	//iterate over num indices and add traingles
	for (int32 i = 0; i < indicesData.Indices.Num(); i++)
	{
		uint32 a = 0;
		a = indicesData.Indices[i];
		Tris.Add(a);
	}

	//Create the procedural mesh
	ProcMeshComponent->CreateMeshSection(0, VerticesArray, Tris, Normals, UV, Colors, Tangents, true);
}

Hi, tofmedPOST:
thank you so much for your greatest work done here, but there is a little problem in your code: error C2065: ‘SkinWeights’: undeclared identifier, how can I get the value of the SkinWeights variable?

Oh, I figure it out now:
add FSkinWeightVertexBuffer* SkinWeights = SkeletalMeshComponent->GetSkinWeightBuffer(LODIndex); before line 21 and it works fine. thanks a lot for your amazing work!

Oops, looks like i forgot a line - I’ve updated my answer, so you shouldn’t be seeing errors now :slight_smile:

This is cool! How would I go about implementing this code? I’m not very keen on C++ just yet. Would I make a Blueprint Function Library ? What would I include ? Thanks!

I would also like to know how this is implemented in blueprints, please

Works like a charm, thank you very much for sharing your knowledge!

Hello!
Thanks for the excellent solution; it helped me a lot!

A small addition: if the mesh has multiple render sections, this code will copy only the first one. It is easily solved by adding a loop and iterating through all DataArray.RenderSections.
And then offset the vertex indexes by DataArray.RenderSections[SectionCount].BaseVertexIndex.

But I have a different but related question: does anybody know how to pick only the vertexes, which have weights associated with some particular bone?
I try to create a dynamic dismemberment system, which would work on with “solid” skeletal meshes without any pre-cutting.
It already works, but it is not very efficient because each time, I have to copy a lot of “unused” vertices and slice them afterwards, but I don’t like this.
FSkinWeightVertexBuffer’s method GetBoneIndex(VertexIndex, InfluenceIndex) seems to be the solution. However, due to a lack of documentation, I am not sure that I use it properly (e.g. I still do not completely get what InfluenceIndex is).
Any ideas?

2 Likes