@AnderGraw 's code works but only does the first mesh part, it returns in the loop instead of getting all the mesh sections with materials.
I fixed it and also included @Xanfar001 's stuff for 5.1.
Also separated the save path and the asset name as it’s cleaner.
It works great, I was able to make my mesh slicer thanks for everyone who posted code snippets <3
The code for saving a procedural mesh to static mesh via BFL:
//Hallo from Unreal Forums
UStaticMesh* UWeedFarmerBFL::SaveProcmesh(UProceduralMeshComponent* ProcMesh, FString SavePath, FString Name)
{
UProceduralMeshComponent* ProcMeshComp = ProcMesh;
if (ProcMeshComp != nullptr)
{
FString PackageName = SavePath;
FRawMesh RawMesh;
TArray<UMaterialInterface*> MeshMaterials;
const int32 NumSections = ProcMeshComp->GetNumSections();
int32 VertexBase = 0;
for (int32 SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
{
FProcMeshSection* ProcSection = ProcMeshComp->GetProcMeshSection(SectionIdx);
// Copy verts
for (FProcMeshVertex& Vert : ProcSection->ProcVertexBuffer)
{
RawMesh.VertexPositions.Add(FVector3f(Vert.Position));
}
// Copy 'wedge' info
int32 NumIndices = ProcSection->ProcIndexBuffer.Num();
for (int32 IndexIdx = 0; IndexIdx < NumIndices; IndexIdx++)
{
int32 Index = ProcSection->ProcIndexBuffer[IndexIdx];
RawMesh.WedgeIndices.Add(Index + VertexBase);
FProcMeshVertex& ProcVertex = ProcSection->ProcVertexBuffer[Index];
FVector3f TangentX = FVector3f(ProcVertex.Tangent.TangentX);
FVector3f TangentZ = FVector3f(ProcVertex.Normal);
FVector3f TangentY = FVector3f(
(TangentX ^ TangentZ).GetSafeNormal() * (ProcVertex.Tangent.bFlipTangentY ? -1.f : 1.f));
RawMesh.WedgeTangentX.Add(TangentX);
RawMesh.WedgeTangentY.Add(TangentY);
RawMesh.WedgeTangentZ.Add(TangentZ);
RawMesh.WedgeTexCoords[0].Add(FVector2f(ProcVertex.UV0));
RawMesh.WedgeColors.Add(ProcVertex.Color);
}
// copy face info
int32 NumTris = NumIndices / 3;
for (int32 TriIdx = 0; TriIdx < NumTris; TriIdx++)
{
RawMesh.FaceMaterialIndices.Add(SectionIdx);
RawMesh.FaceSmoothingMasks.Add(0); // Assume this is ignored as bRecomputeNormals is false
}
// Remember material
MeshMaterials.Add(ProcMeshComp->GetMaterial(SectionIdx));
// Update offset for creating one big index/vertex buffer
VertexBase += ProcSection->ProcVertexBuffer.Num();
}
// If we got some valid data.
if (RawMesh.VertexPositions.Num() > 3 && RawMesh.WedgeIndices.Num() > 3)
{
// Then find/create it.
UPackage* Package = CreatePackage(*PackageName);
check(Package);
// Create StaticMesh object
UStaticMesh* StaticMesh = NewObject<UStaticMesh>(Package, FName(*Name), RF_Public | RF_Standalone);
StaticMesh->InitResources();
FGuid::NewGuid() = StaticMesh->GetLightingGuid();
//StaticMesh->GetLightingGuid() = FGuid::NewGuid();
// Create a Source Model then set it to variable
StaticMesh->AddSourceModel();
FStaticMeshSourceModel& SrcModel = StaticMesh->GetSourceModel(0);
// Add source to new StaticMesh
SrcModel.BuildSettings.bRecomputeNormals = false;
SrcModel.BuildSettings.bRecomputeTangents = false;
SrcModel.BuildSettings.bRemoveDegenerates = false;
SrcModel.BuildSettings.bUseHighPrecisionTangentBasis = false;
SrcModel.BuildSettings.bUseFullPrecisionUVs = false;
SrcModel.BuildSettings.bGenerateLightmapUVs = true;
SrcModel.BuildSettings.SrcLightmapIndex = 0;
SrcModel.BuildSettings.DstLightmapIndex = 1;
SrcModel.RawMeshBulkData->SaveRawMesh(RawMesh);
// Copy materials to new mesh
for (UMaterialInterface* Material : MeshMaterials)
{
StaticMesh->GetStaticMaterials().Add(FStaticMaterial(Material));
}
//Set the Imported version before calling the build
StaticMesh->ImportVersion = EImportStaticMeshVersion::LastVersion;
// Build mesh from source
StaticMesh->Build(false);
StaticMesh->PostEditChange();
// Notify asset registry of new asset
FAssetRegistryModule::AssetCreated(StaticMesh);
return StaticMesh;
}
}
return nullptr;
}