Files
UnrealEngineUWP/Engine/Source/Developer/WorldPartitionHLODUtilities/Private/HLODBuilderMeshApproximate.cpp
Sebastien Lussier 9e487bd467 Support batching components using HLODBatchingPolicy == EHLODBatchingPolicy::Instancing as instanced in the MeshApproximate & MeshSimplify HLOD builders
#rb luc.eygasier
#robomerge private-frosty

[CL 16737956 by Sebastien Lussier in ue5-main branch]
2021-06-21 22:05:11 -04:00

188 lines
7.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "HLODBuilderMeshApproximate.h"
#include "Algo/ForEach.h"
#include "Algo/Transform.h"
#include "WorldPartition/HLOD/HLODActor.h"
#include "WorldPartition/HLOD/HLODLayer.h"
#include "Engine/StaticMesh.h"
#include "Materials/Material.h"
#include "Materials/MaterialInstance.h"
#include "MaterialUtilities.h"
#include "Modules/ModuleManager.h"
#include "IGeometryProcessingInterfacesModule.h"
#include "GeometryProcessingInterfaces/ApproximateActors.h"
#include "HLODBuilderInstancing.h"
TArray<UPrimitiveComponent*> FHLODBuilder_MeshApproximate::CreateComponents(AWorldPartitionHLOD* InHLODActor, const UHLODLayer* InHLODLayer, const TArray<UPrimitiveComponent*>& InSubComponents)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FHLODBuilder_MeshApproximate::CreateComponents);
TSet<AActor*> Actors;
TArray<UPrimitiveComponent*> InstancedComponents;
// Filter the input components
for (UPrimitiveComponent* SubComponent : InSubComponents)
{
if (!SubComponent)
{
continue;
}
switch (SubComponent->HLODBatchingPolicy)
{
case EHLODBatchingPolicy::None:
Actors.Add(SubComponent->GetOwner());
break;
case EHLODBatchingPolicy::Instancing:
InstancedComponents.Add(SubComponent);
break;
case EHLODBatchingPolicy::MeshSection:
InstancedComponents.Add(SubComponent);
UE_LOG(LogHLODBuilder, Warning, TEXT("EHLODBatchingPolicy::MeshSection is not yet supported by the MeshApproximate builder."));
break;
}
}
IGeometryProcessingInterfacesModule& GeomProcInterfaces = FModuleManager::Get().LoadModuleChecked<IGeometryProcessingInterfacesModule>("GeometryProcessingInterfaces");
IGeometryProcessing_ApproximateActors* ApproxActorsAPI = GeomProcInterfaces.GetApproximateActorsImplementation();
//
// Construct options for ApproximateActors operation
//
const FMeshApproximationSettings& UseSettings = InHLODLayer->GetMeshApproximationSettings();
IGeometryProcessing_ApproximateActors::FOptions Options = ApproxActorsAPI->ConstructOptions(UseSettings);
Options.BasePackagePath = InHLODActor->GetPackage()->GetName();
Options.bGenerateLightmapUVs = false;
Options.bCreatePhysicsBody = false;
// Material baking settings
Options.BakeMaterial = GEngine->DefaultHLODFlattenMaterial;
Options.BaseColorTexParamName = FName("BaseColorTexture");
Options.NormalTexParamName = FName("NormalTexture");
Options.MetallicTexParamName = FName("MetallicTexture");
Options.RoughnessTexParamName = FName("RoughnessTexture");
Options.SpecularTexParamName = FName("SpecularTexture");
Options.EmissiveTexParamName = FName("EmissiveHDRTexture");
Options.bUsePackedMRS = true;
Options.PackedMRSTexParamName = FName("PackedTexture");
// Gather bounds of the input components
auto GetActorsBounds = [&]() -> FBoxSphereBounds
{
FBoxSphereBounds Bounds;
bool bFirst = true;
for (UPrimitiveComponent* Component : InSubComponents)
{
FBoxSphereBounds ComponentBounds = Component->Bounds;
Bounds = bFirst ? ComponentBounds : Bounds + ComponentBounds;
bFirst = false;
}
return Bounds;
};
// Compute texel density if needed, depending on the TextureSizingType setting
ETextureSizingType TextureSizingType = UseSettings.MaterialSettings.TextureSizingType;
float TexelDensityPerMeter = 0.0f;
IGeometryProcessing_ApproximateActors::ETextureSizePolicy TextureSizePolicy = IGeometryProcessing_ApproximateActors::ETextureSizePolicy::TextureSize;
if (TextureSizingType == ETextureSizingType::TextureSizingType_AutomaticFromTexelDensity)
{
TexelDensityPerMeter = UseSettings.MaterialSettings.TargetTexelDensityPerMeter;
TextureSizePolicy = IGeometryProcessing_ApproximateActors::ETextureSizePolicy::TexelDensity;
}
else if (TextureSizingType == ETextureSizingType::TextureSizingType_AutomaticFromMeshScreenSize)
{
TexelDensityPerMeter = FMaterialUtilities::ComputeRequiredTexelDensityFromScreenSize(UseSettings.MaterialSettings.MeshMaxScreenSizePercent, GetActorsBounds().SphereRadius);
TextureSizePolicy = IGeometryProcessing_ApproximateActors::ETextureSizePolicy::TexelDensity;
}
else if (TextureSizingType == ETextureSizingType::TextureSizingType_AutomaticFromMeshDrawDistance)
{
TexelDensityPerMeter = FMaterialUtilities::ComputeRequiredTexelDensityFromDrawDistance(UseSettings.MaterialSettings.MeshMinDrawDistance, GetActorsBounds().SphereRadius);
TextureSizePolicy = IGeometryProcessing_ApproximateActors::ETextureSizePolicy::TexelDensity;
}
Options.MeshTexelDensity = TexelDensityPerMeter;
Options.TextureSizePolicy = TextureSizePolicy;
// run actor approximation computation
IGeometryProcessing_ApproximateActors::FResults Results;
ApproxActorsAPI->ApproximateActors(Actors.Array(), Options, Results);
TArray<UPrimitiveComponent*> Components;
if (Results.ResultCode == IGeometryProcessing_ApproximateActors::EResultCode::Success)
{
auto FixupAsset = [&InHLODActor](UObject* Asset)
{
Asset->ClearFlags(RF_Public | RF_Standalone);
Asset->Rename(nullptr, InHLODActor->GetPackage(), REN_NonTransactional | REN_DontCreateRedirectors | REN_ForceNoResetLoaders);
};
Algo::ForEach(Results.NewMeshAssets, FixupAsset);
Algo::ForEach(Results.NewMaterials, FixupAsset);
Algo::ForEach(Results.NewTextures, FixupAsset);
for (UStaticMesh* StaticMesh : Results.NewMeshAssets)
{
UStaticMeshComponent* Component = NewObject<UStaticMeshComponent>(InHLODActor);
Component->SetStaticMesh(StaticMesh);
DisableCollisions(Component);
Components.Add(Component);
}
for (UMaterialInterface* Material : Results.NewMaterials)
{
UMaterialInstance* MaterialInst = CastChecked<UMaterialInstance>(Material);
FStaticParameterSet StaticParameterSet;
auto SetStaticSwitch = [&StaticParameterSet](FName ParamName, bool bSet)
{
if (bSet)
{
FStaticSwitchParameter SwitchParameter;
SwitchParameter.ParameterInfo.Name = ParamName;
SwitchParameter.Value = true;
SwitchParameter.bOverride = true;
StaticParameterSet.StaticSwitchParameters.Add(SwitchParameter);
}
};
// Set proper switches needed by our base flatten material
SetStaticSwitch("UseBaseColor", Options.bBakeBaseColor);
SetStaticSwitch("UseRoughness", Options.bBakeRoughness);
SetStaticSwitch("UseMetallic", Options.bBakeMetallic);
SetStaticSwitch("UseSpecular", Options.bBakeSpecular);
SetStaticSwitch("UseEmissiveHDR", Options.bBakeEmissive);
SetStaticSwitch("UseNormal", Options.bBakeNormalMap);
SetStaticSwitch("PackMetallic", Options.bUsePackedMRS);
SetStaticSwitch("PackSpecular", Options.bUsePackedMRS);
SetStaticSwitch("PackRoughness", Options.bUsePackedMRS);
// Force initializing the static permutations according to the switches we have set
MaterialInst->UpdateStaticPermutation(StaticParameterSet);
MaterialInst->InitStaticPermutation();
MaterialInst->PostEditChange();
}
}
// Batch instances
if (InstancedComponents.Num())
{
FHLODBuilder_Instancing InstancingHLODBuilder;
Components.Append(InstancingHLODBuilder.CreateComponents(InHLODActor, nullptr, InstancedComponents));
}
return Components;
}