当前位置:网站首页>Mesh merging under ue4/ue5 runtime
Mesh merging under ue4/ue5 runtime
2022-07-07 15:43:00 【WhiteTian】
Original article , Reprint please indicate the source .
StaticMesh The merger of
Preface
Engine version :4.27.2
The premise of the merger : stay UE4.26.2 after , Runtime components are allowed UStaticmesh. The previous method only supports importing under the editor ,
After importing, it will be converted to UStaticMesh Of RenderData Rendering ;
Why merge :
The source of demand is software. We want to use UE4.27.2 Of runtime Under the udatasmith Import function ,
But because datasmith The original intention of our design is to split the model as small as possible , The particle size is very small .
So there are udatasmith After importing, there will be tens of thousands of... In the level , Very low frame rate .
That's why there is this article Merge at run time StaticMesh.
The optimization scheme of the combined batch is as follows
In fact, there are many that can be approved together .
therefore , Here I will focus on udatasmith Import this function , Studied the scheme of joint approval ;
programme | advantage | shortcoming |
---|---|---|
1> modify datasmith Import the code of some plug-ins | Highest efficiency | Difficult to maintain |
2> Make your own set | The efficiency is lower than the scheme 1, Easy maintenance | Easy maintenance |
3> modify datasmith Export plug-ins | Not sure | Difficult to maintain |
Which scheme to use ?
programme 1 In a word , Change DataSmith Source code , I think efficiency is the best .
Why? :
Let's start with the plan 1 How to do it : One by one actor Not yet spawn,mesh Not yet build,collsion, There is no such information as material build Before , Let's filter in advance Mesh Can be merged , After that spawn MeshActor,build StaticMesh Of vertex,collision,material.
Let's talk about the plan 2 How to do it : be-all actor Already in the world spawn Come out ,StaticMesh Of vertex,collision,material This information has been build Okay . Then filter what is good Mesh Can be merged , After that spawn MeshActor,build StaticMesh Of vertex,collision,material.
The scheme is implemented temporarily 2
In contrast , programme 1 It's better than the plan 2 Efficient . But the plan 1 It's more troublesome to change , And I don't think it's easy to maintain . After watching it all day , I realized the scheme first 2.
Video effects :Merge Then the frame rate and DC Significantly improve Jump Watch
UE4/UE5 Runtime Lower merger Mesh
Class diagram
Editor With the implementation of the
Reference resources MergeActor Tool
Use the... Under the editor MergeActorTool The function of the tool , The merging logic will soon be implemented in the editor .Standlone You can also merge .
But it should be noted that this can only be used under the editor , Take a break when you pack .
The specific code of merging under the editor is as follows , As a reference :
// Merge method under editor
void UMyBlueprintFunctionLibrary::MergeMy(const TArray<UPrimitiveComponent*>& ComponentsToMerge, UWorld* World,
const FMeshMergingSettings& InSettings, UMaterialInterface* InBaseMaterial,
UPackage* InOuter, const FString& InBasePackageName,
TArray<UObject*>& OutAssetsToSync, FVector& OutMergedActorLocation,
const float ScreenSize, bool bSilent /*= false*/, FString AppendName)
{
const IMeshMergeUtilities& MeshUtilities = FModuleManager::Get().
LoadModuleChecked<IMeshMergeModule>("MeshMergeUtilities").GetUtilities();
MeshUtilities.MergeComponentsToStaticMeshWithName(ComponentsToMerge, GWorld, InSettings, InBaseMaterial, InOuter, InBasePackageName,
OutAssetsToSync, OutMergedActorLocation, ScreenSize, bSilent, AppendName);
}
// Merge specific logic , Put the same material Mesh Pass it in to complete the merger .
TArray<UObject*> OutAssetsToSync;
FVector OutMergedActorLocation;
const float ScreenAreaSize = TNumericLimits<float>::Max();
FMeshMergingSettings setting;
setting.bMergePhysicsData = 1;
MergeMy(mergedata.Value, GWorld,
setting, nullptr, GetTransientPackage(), FString(),
OutAssetsToSync, OutMergedActorLocation,
ScreenAreaSize, true, mergedata.Key);
UStaticMesh* UtilitiesMergedMesh = nullptr;
if (!OutAssetsToSync.FindItemByClass(&UtilitiesMergedMesh))
{
// Error, TEXT("MergeStaticMeshActors failed. No mesh was created.
continue;
}
for (auto obj : OutAssetsToSync)
{
auto umesh = Cast<UStaticMesh>(obj);
if (!umesh)
continue;
/*auto mat0 = umesh->GetMaterial(0); if (!UKismetSystemLibrary::IsValid(mat0)) continue;*/
OutMergedActorLocation+=FVector(0,0,500);
auto MergedActor = GWorld->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(), OutMergedActorLocation, FRotator(0, 0, 0));
if (MergedActor)
{
MergedActor->SetMobility(EComponentMobility::Movable);
if (!MergedActor->GetStaticMeshComponent())
continue;
MergedActor->GetStaticMeshComponent()->SetStaticMesh(umesh);
if (mergedata.Value.Num() > 0)
{
UStaticMeshComponent* pSTM = Cast<UStaticMeshComponent>(mergedata.Value[0]);
if (pSTM)
{
//umesh->SetStaticMaterials(pSTM->GetStaticMesh()->GetStaticMaterials());
}
}
GWorld->UpdateCullDistanceVolumes(MergedActor, MergedActor->GetStaticMeshComponent());
MergedActor->AttachToActor(RootActor, FAttachmentTransformRules::KeepWorldTransform);
#if WITH_EDITOR
MergedActor->SetActorLabel(UKismetSystemLibrary::GetDisplayName(umesh));
#endif // endif
}
// Delete the replaced RootActor
for (auto willremovecomp : mergedata.Value)
{
if(!IsValid(DeleteActorArray[willremovecomp]))
continue;
if(!DeleteActorArray[willremovecomp]->IsValidLowLevel())
continue;
TArray<UActorComponent*> OutComponent;
OutComponent = DeleteActorArray[willremovecomp]->K2_GetComponentsByClass(UStaticMeshComponent::StaticClass());
if (OutComponent.Num() < 2)
{
GWorld->DestroyActor(DeleteActorArray[willremovecomp]);
}
else
{
willremovecomp->DestroyComponent();
}
}
}
Runtime With the implementation of the
difficulty 1,StaticMesh Of RenderData turn FMeshDescription
In fact, if you've seen this StaticMesh You should know , The code merged under the editor is used under the editor StaticMesh Unique data to merge , This is the picture below . The variables used are SourceModels
also , Under the editor StaticMesh The build will eventually call Build Method , But these are not available at runtime .
We need to use... In the new version of the engine BuildFromStaticMeshDescriptions To generate UStaticMesh.
BuildFromStaticMeshDescriptions What this method needs is FMeshDescription,FMeshDescription After importing in the editor, there will be , But at runtime UStaticMesh Of SourceModels Does not exist. , What do I do ?
We need to push back , The final rendered data exists UStaticMesh Of RenderData in , So we start from RenderData It turns the data into FMeshDescription Just array .
In turn, merge each one that can be merged Mesh The data from RenderData convert to FMeshDescription, Then put these
FMeshDescription Add once , Give it to UStaticMesh Of BuildFromStaticMeshDescriptions Pass it in and it's done ( Note the size of the data here ,UE Serialization of cannot exceed 2G, But fortunately, we wrote this by ourselves , And then splicing FMeshDescription Let's just control the memory when we need it , This is also related to the speed of merger )
To sum up, the specific steps are :
1>RenderData turn FMeshDescription
2> Splice all FMeshDescription
3> call BuildFromStaticMeshDescriptions
difficulty 2,StaticMesh Build complex collisions
To build complex collisions , So call
UBodySetup->CreatePhysicsMeshes(), If you follow carefully , When you go in, you'll find , stay Runtime Next ,build Collision will call ProcessFormatData_PhysX perhaps ProcessFormatData_Chaos, But the preconditions must be met IsRuntime The judgment of the .
The reason I found this is , After the merger , I'm creating UStaticMesh Objects are written in a common way ,NewObect(xxxxxxx), It turns out that IsRuntime My judgment there has always been false.
if (IsRuntime(this))
{
#if WITH_PHYSX && PHYSICS_INTERFACE_PHYSX
bClearMeshes = !RuntimeCookPhysics_PhysX();
#elif WITH_CHAOS
bClearMeshes = !RuntimeCookPhysics_Chaos();
#endif
}
void UBodySetup::CreatePhysicsMeshes()
{
TRACE_CPUPROFILER_EVENT_SCOPE(UBodySetup::CreatePhysicsMeshes);
SCOPE_CYCLE_COUNTER(STAT_CreatePhysicsMeshes);
// Create meshes from cooked data if not already done
if(bCreatedPhysicsMeshes)
{
return;
}
// If we don't have any convex/trimesh data we can skip this whole function
if (bNeverNeedsCookedCollisionData)
{
return;
}
bool bClearMeshes = true;
// Find or create cooked physics data
static FName PhysicsFormatName(FPlatformProperties::GetPhysicsFormat());
FByteBulkData* FormatData = GetCookedData(PhysicsFormatName);
// On dedicated servers we may be cooking generic data and sharing it
if (FormatData == nullptr && IsRunningDedicatedServer())
{
FormatData = GetCookedData(FGenericPlatformProperties::GetPhysicsFormat());
}
if (FormatData)
{
#if WITH_PHYSX && PHYSICS_INTERFACE_PHYSX
bClearMeshes = !ProcessFormatData_PhysX(FormatData);
#elif WITH_CHAOS
bClearMeshes = !ProcessFormatData_Chaos(FormatData);
#endif
}
else
{
if (IsRuntime(this))// This place is in Runtime Next, if you use UStaticMesh Words , It's impossible to pass .
{
#if WITH_PHYSX && PHYSICS_INTERFACE_PHYSX
bClearMeshes = !RuntimeCookPhysics_PhysX();
#elif WITH_CHAOS
bClearMeshes = !RuntimeCookPhysics_Chaos();
#endif
}
}
// fix up invalid transform to use identity
// this can be here because BodySetup isn't blueprintable
if ( GetLinkerUE4Version() < VER_UE4_FIXUP_BODYSETUP_INVALID_CONVEX_TRANSFORM )
{
for (int32 i=0; i<AggGeom.ConvexElems.Num(); ++i)
{
if ( AggGeom.ConvexElems[i].GetTransform().IsValid() == false )
{
AggGeom.ConvexElems[i].SetTransform(FTransform::Identity);
}
}
}
#if WITH_CHAOS
// For drawing of convex elements we require an index buffer, previously we could
// get this from a PxConvexMesh but Chaos doesn't maintain that data. Instead now
// it is a part of the element rather than the physics geometry, if we load in an
// element without that data present, generate a convex hull from the convex vert
// data and extract the index data from there.
for(FKConvexElem& Convex : AggGeom.ConvexElems)
{
Convex.ComputeChaosConvexIndices();
}
#endif
if(bClearMeshes)
{
ClearPhysicsMeshes();
}
bCreatedPhysicsMeshes = true;
}
After looking at the code , Follow code , I found a solution .
1> First of all, you need to UStaticMesh Derive a class ;
2> And this kind of bAllowCPUAccess It has to be for true;
3> And reload GetWorld();
Then I'm adding one SetWorld Method ;
The specific code of this class is as follows :
/* * from UStaticMesh Derived classes , Allow collision meshes to be cooked at runtime * Do that ,bAllowCPUAccess It has to be for true, And the way GetWorld() A valid... Must be returned world * Otherwise, in the Cook There was a IsRuntime() My judgment is always false */
UCLASS()
class EASYKITRUNTIMEMERGEMESH_API UEKRMM_RuntimeMesh : public UStaticMesh
{
GENERATED_BODY()
public:
UEKRMM_RuntimeMesh()
: World(nullptr)
{
// Set up bAllowCPUAccess by true, Allows you to copy rendered data triangles into the collision mesh
bAllowCPUAccess = true;
}
// UObject Cover
// Overrides allow cooking to collide with the mesh , Simple and complex , From the static grid at run time
virtual UWorld* GetWorld() const override {
return World ? World : UStaticMesh::GetWorld(); }
// end UObject Cover
// Use an effective world , Allow collision meshes , Simple and complex , From the static grid at run time
void SetWorld(UWorld* InWorld) {
World = InWorld; }
private:
UWorld* World;
};
It's easy to use , as follows , And then I'll call UBodySetup->CreatePhysicsMeshes() Just OK 了 :
UEKRMM_RuntimeMesh* StaticMesh = NewObject< UEKRMM_RuntimeMesh >(GetTransientPackage(), MeshName, RF_Public | RF_Standalone);
if(!StaticMesh)
continue;
StaticMesh->InitResources();
// The world must be set
StaticMesh->SetWorld(RootActor->GetWorld());
difficulty 3,StaticMesh texture of material
Plug in encapsulation , Introduction to existing functions and subsequent plans
Features currently supported :
1> All of the same material mesh Merge together : Pass in a AActor Object as RootActor, To be able to RootActor All materials under the are the same UStaticmeshComponent Merge into a single UStaticMesh;
2> The material is correct
3> Ensure there are complex collisions
4> The coordinates are correct
5> To be added : Size calculation before merging , Block : The main purpose is to meet serialization and merge efficiency
6> To be added : Facet reduction plug-in , When merging, you can dynamically reduce faces , I'm going to get a plug-in out as well , Runtime subtraction algorithm
7> To be added :USkeletalMesh Of Merge
8> To be added : serialize
Reference article
Datasmith Runtime Official Blog
Unreal Engine 4.27 Datasmith Runtime Import
UE – StaticMesh analysis
边栏推荐
- 【搞船日记】【Shapr3D的STL格式转Gcode】
- [markdown grammar advanced] make your blog more exciting (IV: set font style and color comparison table)
- 2022 all open source enterprise card issuing network repair short website and other bugs_ 2022 enterprise level multi merchant card issuing platform source code
- Shader Language
- [target detection] yolov5 Runtong voc2007 data set
- The "go to definition" in VS2010 does not respond or prompts the solution of "symbol not found"
- Annexb and avcc are two methods of data segmentation in decoding
- Cocos uses custom material to display problems
- Database exception resolution caused by large table delete data deletion
- How to release NFT in batches in opensea (rinkeby test network)
猜你喜欢
[quick start for Digital IC Validation] 26. Ahb - sramc (6) for system verilog project practice (Basic Points of APB Protocol)
Guangzhou Development Zone enables geographical indication products to help rural revitalization
Iterator and for of.. loop
【数字IC验证快速入门】22、SystemVerilog项目实践之AHB-SRAMC(2)(AMBA总线介绍)
【数字IC验证快速入门】29、SystemVerilog项目实践之AHB-SRAMC(9)(AHB-SRAMC SVTB Overview)
[quick start of Digital IC Verification] 26. Ahb-sramc of SystemVerilog project practice (6) (basic points of APB protocol)
Gd32 F3 pin mapping problem SW interface cannot be burned
Wechat applet 01
webgl_ Enter the three-dimensional world (1)
微信小程序 01
随机推荐
MongoD管理数据库的方法介绍
Vertex shader to slice shader procedure, varying variable
[quick start of Digital IC Verification] 26. Ahb-sramc of SystemVerilog project practice (6) (basic points of APB protocol)
【数字IC验证快速入门】23、SystemVerilog项目实践之AHB-SRAMC(3)(AHB协议基本要点)
什麼是數據泄露
Shader Language
【Markdown语法高级】让你的博客更精彩(四:设置字体样式以及颜色对照表)
./ Functions of configure, make and make install
VS2005 strange breakpoint is invalid or member variable value cannot be viewed
[quick start of Digital IC Verification] 18. Basic grammar of SystemVerilog learning 5 (concurrent threads... Including practical exercises)
Getting started with webgl (1)
leetcode 241. Different ways to add parentheses design priority for operational expressions (medium)
Create lib Library in keil and use lib Library
How to create Apple Developer personal account P8 certificate
【微信小程序】Chapter(5):微信小程序基础API接口
How to build your own super signature system (yunxiaoduo)?
The "go to definition" in VS2010 does not respond or prompts the solution of "symbol not found"
MySQL bit类型解析
[quick start of Digital IC Verification] 22. Ahb-sramc of SystemVerilog project practice (2) (Introduction to AMBA bus)
Wechat applet 01