Xanfar001
(Xanfar001)
February 16, 2023, 1:28am
23
I was able to fix the ‘AddSourceModel’ issue usng the following code for that part in 5.1. You have to add an empty source model and then modify it
// 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);
Hope this helps. Thanks to you all when I needed this!
1 Like
PreyK
(PreyK)
March 23, 2023, 9:40am
24
@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;
}
2 Likes
eray_ozr
(eray_ozr)
April 18, 2023, 7:13pm
26
I think this addresses to another usecase but it shouldn’t work on packaged runtime.
eray_ozr
(eray_ozr)
April 18, 2023, 7:16pm
27
I used this code (based on yours) and it worked on packaged runtime.
if (IsValid(In_Pmc) == false)
{
return false;
}
FName PMC_Name = FName(*In_Pmc->GetName());
UStaticMesh* StaticMesh = NewObject<UStaticMesh>(GetTransientPackage(), PMC_Name, EObjectFlags::RF_Transient);
StaticMesh->bAllowCPUAccess = true;
StaticMesh->NeverStream = true;
StaticMesh->InitResources();
StaticMesh->SetLightingGuid();
FMeshDescription PMC_Description = BuildMeshDescription(In_Pmc);
UStaticMeshDescription* SM_Description = StaticMesh->CreateStaticMeshDescription();
SM_Description->SetMeshDescription(PMC_Description);
StaticMesh->BuildFromStaticMeshDescriptions({ SM_Description }, false);
// Collision
StaticMesh->CalculateExtendedBounds();
StaticMesh->SetBodySetup(In_Pmc->ProcMeshBodySetup);
#if WITH_EDITOR
StaticMesh->PostEditChange();
#endif
StaticMesh->MarkPackageDirty();
Out_Sm = StaticMesh;
return true;
but the problem is I can’t use transcluent materials with it. I just deleted all material oriented codes and just set material from static mesh component with blueprint. Transcluent ones dissapear completely. There is collision and static mesh is not null but I think there is a problem with buffers.
2 Likes
Xiaodu-513
(Xiaodu-513)
August 31, 2023, 11:02am
28
Have you resolved this issue? I have also encountered the same issue and cannot package the Windows platform properly
lumingfei
(lumingfei)
September 5, 2023, 1:02pm
29
// Create StaticMesh object
UStaticMesh* StaticMesh = NewObject();
// MATERIALS
TSet<UMaterialInterface*> UniqueMaterials;
const int32 NumSections = ProceduralMeshComponent->GetNumSections();
for (int32 SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
{
FProcMeshSection* ProcSection = ProceduralMeshComponent->GetProcMeshSection(SectionIdx);
UMaterialInterface* Material = ProceduralMeshComponent->GetMaterial(SectionIdx);
if (Material == nullptr)
{
Material = UMaterial::GetDefaultMaterial(MD_Surface);
}
UniqueMaterials.Add(Material);
}
// Copy materials to new mesh
for (auto* Material : UniqueMaterials)
{
StaticMesh->GetStaticMaterials().Add(FStaticMaterial(Material));
}
FMeshDescription MeshDescription = BuildMeshDescription(ProceduralMeshComponent);
FStaticMeshAttributes StaticMeshAttributes(MeshDescription);
StaticMeshAttributes.Register();
// Build the static mesh render data, one FMeshDescription* per LOD.
TArray<const FMeshDescription*> MeshDescriptionPtrs;
MeshDescriptionPtrs.Emplace(&MeshDescription);
UStaticMesh::FBuildMeshDescriptionsParams BuildParams;
BuildParams.bAllowCpuAccess = true;
BuildParams.bBuildSimpleCollision = false;
StaticMesh->BuildFromMeshDescriptions(MeshDescriptionPtrs, BuildParams);
// Collision
StaticMesh->SetBodySetup(ProceduralMeshComponent->ProcMeshBodySetup);
//// SIMPLE COLLISION
if (!ProceduralMeshComponent->bUseComplexAsSimpleCollision)
{
StaticMesh->CreateBodySetup();
UBodySetup* NewBodySetup = StaticMesh->GetBodySetup();
NewBodySetup->BodySetupGuid = FGuid::NewGuid();
NewBodySetup->AggGeom.ConvexElems = ProceduralMeshComponent->ProcMeshBodySetup->AggGeom.ConvexElems;
NewBodySetup->bGenerateMirroredCollision = false;
NewBodySetup->bDoubleSidedGeometry = true;
NewBodySetup->CollisionTraceFlag = CTF_UseDefault;
NewBodySetup->CreatePhysicsMeshes();
}
it works in 4.27 runtime.
3 Likes
It worked for me,
however I want to save that mesh as .uasset file if any of you know how I can do that in binary then that will be big help