Hello, I am trying to create a node for Mutable which takes 2 skeletal meshes and merges them together, outputting the merged mesh. We need this as other tech we have a node for requires a full body and head, but we have separate meshes for each.
I currently already have a UMeshMerge : UCustomizableObjectNode node for the editor, a NodeMeshMerge : NodeMesh node for the intermediate node structures, and I’m using ASTOpFixed with an OP_TYPE of ME_MERGE. This works in the sense that mu::MeshMerge does run, but it crashes later in the compile step because its buffer set is missing MUTABLE_VERTEXBUFFER_TEXCOORDS (UnrealConversionUtils.cpp : 340 - const int NumTexCoords = MutableMeshVertexBuffers.GetBufferChannelCount(MUTABLE_VERTEXBUFFER_TEXCOORDS)
I have a feeling that my ad-hoc approach is doing something wrong, so is there a defacto way to approach this? Or better yet, is there a way to do this already that I’m missing? I know that the MeshComponent nodes merge the meshes but it outputs a component and not the mesh itself so it isn’t very useful to us.
Here are the relevant code sections (posting two separate code snippets isnt working for me so sorry for the formatting, I have separated the two snippets by ======'s instead):
`mu::Ptrmu::NodeMesh GenerateMutableSourceMesh(const UEdGraphPin* Pin,
FMutableGraphGenerationContext& GenerationContext,
FMutableGraphMeshGenerationData& MeshData,
uint32 SurfaceMetadataId,
const bool bLinkedToExtendMaterial,
const bool bOnlyConnectedLOD)
{
…
else if (const UExtractMeshFromComponentNode* TypedNodeMeshMerge = Cast(Node))
{
mu::Ptrmu::NodeNSMeshMerge MeshMergeNode = new mu::NodeNSMeshMerge();
Result = MeshMergeNode;
if (const UEdGraphPin* ConnectedPin = FollowInputPin(*TypedNodeMeshMerge->GetMesh0Pin()))
{
FMutableGraphMeshGenerationData ChildMeshData;
mu::Ptrmu::NodeMesh ChildNode = GenerateMutableSourceMesh(ConnectedPin, GenerationContext, ChildMeshData, SurfaceMetadataId, false, bOnlyConnectedLOD);
if (ChildNode)
{
MeshMergeNode->SetMesh0(ChildNode);
}
}
if (const UEdGraphPin* ConnectedPin = FollowInputPin(*TypedNodeMeshMerge->GetMesh1Pin()))
{
FMutableGraphMeshGenerationData ChildMeshData;
mu::Ptrmu::NodeMesh ChildNode = GenerateMutableSourceMesh(ConnectedPin, GenerationContext, ChildMeshData, SurfaceMetadataId, false, bOnlyConnectedLOD);
if (ChildNode)
{
MeshMergeNode->SetMesh1(ChildNode);
}
}
}
void CodeGenerator::GenerateMesh_NSMeshMerge(const FMeshGenerationOptions& InOptions, FMeshGenerationResult& OutResult, const NodeNSMeshMerge* MeshMerge)
{
const NodeNSMeshMerge::Private& Node = *MeshMerge->GetPrivate();
Ptr lastCompOp;
Ptr lastMeshOp;
Ptr mop = new ASTOpFixed();
mop->op.type = OP_TYPE::ME_MERGE;
FMeshGenerationOptions Opts;
Opts.bLayouts = true;
if (Node.Mesh0)
{
FMeshGenerationResult Mesh0Result;
GenerateMesh(Opts, Mesh0Result, Node.Mesh0);
mop->SetChild(mop->op.args.MeshMerge.base, Mesh0Result.MeshOp);
}
if (Node.Mesh1)
{
FMeshGenerationResult Mesh1Result;
GenerateMesh(Opts, Mesh1Result, Node.Mesh1);
mop->SetChild(mop->op.args.MeshMerge.added, Mesh1Result.MeshOp);
}
mop->op.args.MeshMerge.newSurfaceID = 0;
//mergeAd = mop;
OutResult.MeshOp = mop;
}`