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 
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