当前位置:网站首页>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
边栏推荐
- 使用Scrapy框架爬取网页并保存到Mysql的实现
- Ida Pro reverse tool finds the IP and port of the socket server
- 知否|两大风控最重要指标与客群好坏的关系分析
- 从 1.5 开始搭建一个微服务框架链路追踪 traceId
- 2. 堆排序『较难理解的排序』
- 2022全开源企业发卡网修复短网址等BUG_2022企业级多商户发卡平台源码
- XMIND frame drawing tool
- Configure mongodb database in window environment
- [make a boat diary] [shapr3d STL format to gcode]
- 2022 all open source enterprise card issuing network repair short website and other bugs_ 2022 enterprise level multi merchant card issuing platform source code
猜你喜欢
Write sequence frame animation with shader
【目标检测】YOLOv5跑通VOC2007数据集
Steps to create P8 certificate and warehousing account
[quickstart to Digital IC Validation] 20. Basic syntax for system verilog Learning 7 (Coverage Driven... Including practical exercises)
使用cpolar建立一个商业网站(2)
【数字IC验证快速入门】19、SystemVerilog学习之基本语法6(线程内部通信...内含实践练习)
How to create Apple Developer personal account P8 certificate
Zhongang Mining: Fluorite continues to lead the growth of new energy market
使用Scrapy框架爬取网页并保存到Mysql的实现
Unity's ASE achieves full screen sand blowing effect
随机推荐
Ida Pro reverse tool finds the IP and port of the socket server
webgl_ Enter the three-dimensional world (1)
webgl_ Graphic transformation (rotation, translation, zoom)
VS2005 strange breakpoint is invalid or member variable value cannot be viewed
[deep learning] semantic segmentation experiment: UNET network /msrc2 dataset
Shader Language
[Data Mining] Visual Pattern Mining: Hog Feature + cosinus Similarity / K - means Clustering
摘抄的只言片语
知否|两大风控最重要指标与客群好坏的关系分析
Keil5 does not support online simulation of STM32 F0 series
Syntax of generator function (state machine)
The download button and debug button in keil are grayed out
[make a boat diary] [shapr3d STL format to gcode]
写一篇万字长文《CAS自旋锁》送杰伦的新专辑登顶热榜
Iterator and for of.. loop
Cocos creator collision and collision callback do not take effect
Matlab experience summary
Create lib Library in keil and use lib Library
Webcodecs parameter settings -avc1.42e01e meaning
Yunxiaoduo software internal test distribution test platform description document