I think I found a working solution, which works fine in UE_5.0.3 game runtime.
Mostly it was copied from original FProceduralMeshComponentDetails::ClickedOnConvertToStaticMesh() source code. Unfortunatly it failed to package game binaries. So I spent 2 days looking for alternative solution.
Generally I replaced original mesh description commitment [starting from AddSourceModel()], which for whatever reason works only in Editor.
Also make sure you AddCollisionConvexMesh supplied with convex mesh vertices (the same mesh vertices for me) to ProceduralMeshComponent before converting it to StaticMesh if you want your simple collision to work properly. Toggle bUseComplexAsSimpleCollision flag on your ProceduralMeshComponent to false as well.
// PrivateDependencyModuleNames.AddRange(new string[] { "ProceduralMeshComponent", "MeshDescription", });
#include "ProceduralMeshComponent.h"
#include "ProceduralMeshConversion.h"
#include "StaticMeshDescription.h"
UStaticMesh* ULifeUtils::TestFunc(UProceduralMeshComponent* ProcMesh)
{
if (!ProcMesh)
return nullptr;
FMeshDescription MeshDescription = BuildMeshDescription(ProcMesh);
// If we got some valid data.
if (MeshDescription.Polygons().Num() > 0)
{
// Create StaticMesh object
UStaticMesh* StaticMesh = NewObject<UStaticMesh>(ProcMesh/*Package, MeshName, RF_Public | RF_Standalone*/);
StaticMesh->InitResources();
StaticMesh->SetLightingGuid();
// Add source to new StaticMesh
auto Desc = StaticMesh->CreateStaticMeshDescription();
Desc->SetMeshDescription(MeshDescription);
// buildSimpleCol = false, cause it creates box collision based on mesh bounds or whatever :(
StaticMesh->BuildFromStaticMeshDescriptions({ Desc }, false);
//// SIMPLE COLLISION
if (!ProcMesh->bUseComplexAsSimpleCollision )
{
StaticMesh->CreateBodySetup();
UBodySetup* NewBodySetup = StaticMesh->GetBodySetup();
NewBodySetup->BodySetupGuid = FGuid::NewGuid();
NewBodySetup->AggGeom.ConvexElems = ProcMesh->ProcMeshBodySetup->AggGeom.ConvexElems;
NewBodySetup->bGenerateMirroredCollision = false;
NewBodySetup->bDoubleSidedGeometry = true;
// Play around with the flag below if you struggle with collision not working
NewBodySetup->CollisionTraceFlag = CTF_UseDefault;
NewBodySetup->CreatePhysicsMeshes();
}
/* Commented out cause I don't need it
//// MATERIALS
TSet<UMaterialInterface*> UniqueMaterials;
const int32 NumSections = ProcMesh->GetNumSections();
for (int32 SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
{
FProcMeshSection *ProcSection =
ProcMesh->GetProcMeshSection(SectionIdx);
UMaterialInterface *Material = ProcMesh->GetMaterial(SectionIdx);
UniqueMaterials.Add(Material);
}
// Copy materials to new mesh
for (auto* Material : UniqueMaterials)
{
StaticMesh->GetStaticMaterials().Add(FStaticMaterial(Material));
}
*/
// Uncallable in game runtime
// StaticMesh->Build(false);
return StaticMesh;
}
return nullptr;
}