You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
858 lines
29 KiB
C++
858 lines
29 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "BakeMeshAttributeMapsTool.h"
|
|
#include "InteractiveToolManager.h"
|
|
#include "ToolBuilderUtil.h"
|
|
|
|
#include "DynamicMesh3.h"
|
|
#include "DynamicMeshAttributeSet.h"
|
|
#include "MeshTransforms.h"
|
|
#include "MeshDescriptionToDynamicMesh.h"
|
|
#include "Sampling/MeshImageBakingCache.h"
|
|
#include "Sampling/MeshNormalMapBaker.h"
|
|
#include "Sampling/MeshOcclusionMapBaker.h"
|
|
#include "Sampling/MeshCurvatureMapBaker.h"
|
|
#include "Sampling/MeshPropertyMapBaker.h"
|
|
#include "Sampling/MeshResampleImageBaker.h"
|
|
#include "Util/IndexUtil.h"
|
|
|
|
#include "SimpleDynamicMeshComponent.h"
|
|
|
|
#include "Materials/Material.h"
|
|
#include "Materials/MaterialInstanceDynamic.h"
|
|
#include "ImageUtils.h"
|
|
|
|
#include "AssetUtils/Texture2DBuilder.h"
|
|
#include "AssetUtils/MeshDescriptionUtil.h"
|
|
#include "AssetGenerationUtil.h"
|
|
|
|
// required to pass UStaticMesh asset so we can save at same location
|
|
#include "Engine/Classes/Components/StaticMeshComponent.h"
|
|
#include "Engine/Classes/Engine/StaticMesh.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "UBakeMeshAttributeMapsTool"
|
|
|
|
|
|
/*
|
|
* ToolBuilder
|
|
*/
|
|
|
|
|
|
bool UBakeMeshAttributeMapsToolBuilder::CanBuildTool(const FToolBuilderState& SceneState) const
|
|
{
|
|
// NOTE: currently can only bake for UStaticMeshComponent
|
|
int32 NumTargets = ToolBuilderUtil::CountComponents(SceneState, CanMakeComponentTarget);
|
|
return (NumTargets == 1 || NumTargets == 2)
|
|
&& (ToolBuilderUtil::CountComponents(SceneState, [&](UActorComponent* Comp) { return Cast<UStaticMeshComponent>(Comp) != nullptr; }) == NumTargets);
|
|
}
|
|
|
|
UInteractiveTool* UBakeMeshAttributeMapsToolBuilder::BuildTool(const FToolBuilderState& SceneState) const
|
|
{
|
|
UBakeMeshAttributeMapsTool* NewTool = NewObject<UBakeMeshAttributeMapsTool>(SceneState.ToolManager);
|
|
NewTool->SetAssetAPI(AssetAPI);
|
|
|
|
TArray<UActorComponent*> Components = ToolBuilderUtil::FindAllComponents(SceneState, CanMakeComponentTarget);
|
|
TArray<TUniquePtr<FPrimitiveComponentTarget>> MeshComponents;
|
|
for (int32 k = 0; k < Components.Num(); ++k)
|
|
{
|
|
MeshComponents.Add(MakeComponentTarget(Cast<UPrimitiveComponent>(Components[k])));
|
|
}
|
|
|
|
NewTool->SetSelection(MoveTemp(MeshComponents));
|
|
return NewTool;
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<FString> UBakeMeshAttributeMapsToolProperties::GetUVLayerNamesFunc()
|
|
{
|
|
return UVLayerNamesList;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Tool
|
|
*/
|
|
|
|
UBakeMeshAttributeMapsTool::UBakeMeshAttributeMapsTool()
|
|
{
|
|
}
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::SetAssetAPI(IToolsContextAssetAPI* AssetAPIIn)
|
|
{
|
|
AssetAPI = AssetAPIIn;
|
|
}
|
|
|
|
void UBakeMeshAttributeMapsTool::Setup()
|
|
{
|
|
UInteractiveTool::Setup();
|
|
|
|
// copy input MeshDescription and make sure it has initialized normals/tangents
|
|
BaseMeshDescription = MakeShared<FMeshDescription>(*ComponentTargets[0]->GetMesh());
|
|
UE::MeshDescription::InitializeAutoGeneratedAttributes(*BaseMeshDescription, ComponentTargets[0]->GetOwnerComponent(), 0);
|
|
|
|
// create dynamic mesh component to use for live preview
|
|
DynamicMeshComponent = NewObject<USimpleDynamicMeshComponent>(ComponentTargets[0]->GetOwnerActor(), "DynamicMesh");
|
|
DynamicMeshComponent->SetupAttachment(ComponentTargets[0]->GetOwnerActor()->GetRootComponent());
|
|
DynamicMeshComponent->RegisterComponent();
|
|
DynamicMeshComponent->SetWorldTransform(ComponentTargets[0]->GetWorldTransform());
|
|
|
|
// transfer materials
|
|
FComponentMaterialSet MaterialSet;
|
|
ComponentTargets[0]->GetMaterialSet(MaterialSet);
|
|
for (int k = 0; k < MaterialSet.Materials.Num(); ++k)
|
|
{
|
|
DynamicMeshComponent->SetMaterial(k, MaterialSet.Materials[k]);
|
|
}
|
|
|
|
DynamicMeshComponent->TangentsType = EDynamicMeshTangentCalcType::ExternallyCalculated;
|
|
DynamicMeshComponent->InitializeMesh(BaseMeshDescription.Get());
|
|
|
|
BaseMesh.Copy(*DynamicMeshComponent->GetMesh());
|
|
BaseSpatial.SetMesh(&BaseMesh, true);
|
|
BaseMeshTangents = MakeShared<FMeshTangentsd>(&BaseMesh);
|
|
BaseMeshTangents->CopyTriVertexTangents(*DynamicMeshComponent->GetTangents());
|
|
|
|
UMaterial* Material = LoadObject<UMaterial>(nullptr, TEXT("/MeshModelingToolset/Materials/BakePreviewMaterial"));
|
|
check(Material);
|
|
if (Material != nullptr)
|
|
{
|
|
PreviewMaterial = UMaterialInstanceDynamic::Create(Material, GetToolManager());
|
|
DynamicMeshComponent->SetOverrideRenderMaterial(PreviewMaterial);
|
|
}
|
|
|
|
bIsBakeToSelf = (ComponentTargets.Num() == 1);
|
|
|
|
// hide input StaticMeshComponent
|
|
ComponentTargets[0]->SetOwnerVisibility(false);
|
|
|
|
|
|
Settings = NewObject<UBakeMeshAttributeMapsToolProperties>(this);
|
|
Settings->RestoreProperties(this);
|
|
Settings->UVLayerNamesList.Reset();
|
|
int32 FoundIndex = -1;
|
|
for (int32 k = 0; k < BaseMesh.Attributes()->NumUVLayers(); ++k)
|
|
{
|
|
Settings->UVLayerNamesList.Add(FString::FromInt(k));
|
|
if (Settings->UVLayer == Settings->UVLayerNamesList.Last())
|
|
{
|
|
FoundIndex = k;
|
|
}
|
|
}
|
|
if (FoundIndex == -1)
|
|
{
|
|
Settings->UVLayer = Settings->UVLayerNamesList[0];
|
|
}
|
|
AddToolPropertySource(Settings);
|
|
|
|
Settings->WatchProperty(Settings->MapType, [this](EBakeMapType) { bResultValid = false; UpdateOnModeChange(); });
|
|
Settings->WatchProperty(Settings->Resolution, [this](EBakeTextureResolution) { bResultValid = false; });
|
|
Settings->WatchProperty(Settings->UVLayer, [this](FString) { bResultValid = false; });
|
|
Settings->WatchProperty(Settings->bUseWorldSpace, [this](bool) { bDetailMeshValid = false; bResultValid = false; });
|
|
|
|
|
|
NormalMapProps = NewObject<UBakedNormalMapToolProperties>(this);
|
|
NormalMapProps->RestoreProperties(this);
|
|
AddToolPropertySource(NormalMapProps);
|
|
SetToolPropertySourceEnabled(NormalMapProps, false);
|
|
|
|
|
|
OcclusionMapProps = NewObject<UBakedOcclusionMapToolProperties>(this);
|
|
OcclusionMapProps->RestoreProperties(this);
|
|
AddToolPropertySource(OcclusionMapProps);
|
|
SetToolPropertySourceEnabled(OcclusionMapProps, false);
|
|
OcclusionMapProps->WatchProperty(OcclusionMapProps->OcclusionRays, [this](int32) { bResultValid = false; });
|
|
OcclusionMapProps->WatchProperty(OcclusionMapProps->MaxDistance, [this](float) { bResultValid = false; });
|
|
OcclusionMapProps->WatchProperty(OcclusionMapProps->BlurRadius, [this](float) { bResultValid = false; });
|
|
OcclusionMapProps->WatchProperty(OcclusionMapProps->bGaussianBlur, [this](float) { bResultValid = false; });
|
|
OcclusionMapProps->WatchProperty(OcclusionMapProps->BiasAngle, [this](float) { bResultValid = false; });
|
|
|
|
|
|
CurvatureMapProps = NewObject<UBakedCurvatureMapToolProperties>(this);
|
|
CurvatureMapProps->RestoreProperties(this);
|
|
AddToolPropertySource(CurvatureMapProps);
|
|
SetToolPropertySourceEnabled(CurvatureMapProps, false);
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->RangeMultiplier, [this](float) { bResultValid = false; });
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->MinRangeMultiplier, [this](float) { bResultValid = false; });
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->CurvatureType, [this](EBakedCurvatureTypeMode) { bResultValid = false; });
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->ColorMode, [this](EBakedCurvatureColorMode) { bResultValid = false; });
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->Clamping, [this](EBakedCurvatureClampMode) { bResultValid = false; });
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->BlurRadius, [this](float) { bResultValid = false; });
|
|
CurvatureMapProps->WatchProperty(CurvatureMapProps->bGaussianBlur, [this](float) { bResultValid = false; });
|
|
|
|
|
|
Texture2DProps = NewObject<UBakedTexture2DImageProperties>(this);
|
|
Texture2DProps->RestoreProperties(this);
|
|
AddToolPropertySource(Texture2DProps);
|
|
SetToolPropertySourceEnabled(Texture2DProps, false);
|
|
Texture2DProps->WatchProperty(Texture2DProps->UVLayer, [this](float) { bResultValid = false; });
|
|
Texture2DProps->WatchProperty(Texture2DProps->SourceTexture, [this](UTexture2D*) { bResultValid = false; });
|
|
|
|
|
|
VisualizationProps = NewObject<UBakedOcclusionMapVisualizationProperties>(this);
|
|
VisualizationProps->RestoreProperties(this);
|
|
AddToolPropertySource(VisualizationProps);
|
|
|
|
InitializeEmptyMaps();
|
|
|
|
bResultValid = false;
|
|
bDetailMeshValid = false;
|
|
|
|
GetToolManager()->DisplayMessage(
|
|
LOCTEXT("OnStartTool", "Bake Maps. Select Bake Mesh (LowPoly) first, then Detail Mesh second. Texture Assets will be created on Accept. "),
|
|
EToolMessageLevel::UserNotification);
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UBakeMeshAttributeMapsTool::CanAccept() const
|
|
{
|
|
return Settings->Result != nullptr;
|
|
}
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::Shutdown(EToolShutdownType ShutdownType)
|
|
{
|
|
Settings->SaveProperties(this);
|
|
OcclusionMapProps->SaveProperties(this);
|
|
NormalMapProps->SaveProperties(this);
|
|
CurvatureMapProps->SaveProperties(this);
|
|
Texture2DProps->SaveProperties(this);
|
|
VisualizationProps->SaveProperties(this);
|
|
|
|
if (DynamicMeshComponent != nullptr)
|
|
{
|
|
ComponentTargets[0]->SetOwnerVisibility(true);
|
|
|
|
if (ShutdownType == EToolShutdownType::Accept)
|
|
{
|
|
UStaticMeshComponent* StaticMeshComponent = CastChecked<UStaticMeshComponent>(ComponentTargets[0]->GetOwnerComponent());
|
|
UStaticMesh* StaticMeshAsset = StaticMeshComponent->GetStaticMesh();
|
|
check(StaticMeshAsset);
|
|
FString BaseName = ComponentTargets[0]->GetOwnerActor()->GetName();
|
|
|
|
if (AssetAPI != nullptr)
|
|
{
|
|
bool bCreatedAssetOK = false;
|
|
switch (Settings->MapType)
|
|
{
|
|
default:
|
|
check(false);
|
|
break;
|
|
|
|
case EBakeMapType::TangentSpaceNormalMap:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::NormalMap);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_Normals"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
|
|
case EBakeMapType::AmbientOcclusion:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::AmbientOcclusion);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_Occlusion"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
|
|
case EBakeMapType::Curvature:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::Color);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_Curvature"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
|
|
case EBakeMapType::NormalImage:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::Color);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_NormalImg"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
|
|
case EBakeMapType::FaceNormalImage:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::Color);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_FaceNormalImg"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
|
|
case EBakeMapType::PositionImage:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::Color);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_PositionImg"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
|
|
case EBakeMapType::Texture2DImage:
|
|
FTexture2DBuilder::CopyPlatformDataToSourceData(Settings->Result, FTexture2DBuilder::ETextureType::Color);
|
|
bCreatedAssetOK = AssetGenerationUtil::SaveGeneratedTexture2D(AssetAPI, Settings->Result,
|
|
FString::Printf(TEXT("%s_TextureImg"), *BaseName), StaticMeshAsset);
|
|
break;
|
|
}
|
|
ensure(bCreatedAssetOK);
|
|
}
|
|
|
|
}
|
|
|
|
DynamicMeshComponent->UnregisterComponent();
|
|
DynamicMeshComponent->DestroyComponent();
|
|
DynamicMeshComponent = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::Render(IToolsContextRenderAPI* RenderAPI)
|
|
{
|
|
UpdateResult();
|
|
|
|
float GrayLevel = VisualizationProps->BaseGrayLevel;
|
|
PreviewMaterial->SetVectorParameterValue(TEXT("BaseColor"), FVector(GrayLevel, GrayLevel, GrayLevel) );
|
|
float AOWeight = VisualizationProps->OcclusionMultiplier;
|
|
PreviewMaterial->SetScalarParameterValue(TEXT("AOWeight"), AOWeight );
|
|
|
|
FPrimitiveDrawInterface* PDI = RenderAPI->GetPrimitiveDrawInterface();
|
|
FTransform Transform = ComponentTargets[0]->GetWorldTransform();
|
|
}
|
|
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateDetailMesh()
|
|
{
|
|
DetailMesh = MakeShared<FDynamicMesh3>();
|
|
FMeshDescriptionToDynamicMesh Converter;
|
|
TUniquePtr<FPrimitiveComponentTarget>& UseDetailTarget = (bIsBakeToSelf) ? ComponentTargets[0] : ComponentTargets[1];
|
|
Converter.Convert(UseDetailTarget->GetMesh(), *DetailMesh);
|
|
|
|
if (Settings->bUseWorldSpace && bIsBakeToSelf == false)
|
|
{
|
|
FTransform3d DetailToWorld(UseDetailTarget->GetWorldTransform());
|
|
MeshTransforms::ApplyTransform(*DetailMesh, DetailToWorld);
|
|
FTransform3d WorldToBase(ComponentTargets[0]->GetWorldTransform());
|
|
MeshTransforms::ApplyTransform(*DetailMesh, WorldToBase.Inverse());
|
|
}
|
|
|
|
DetailSpatial = MakeShared<FDynamicMeshAABBTree3>();
|
|
DetailSpatial->SetMesh(DetailMesh.Get(), true);
|
|
|
|
bResultValid = false;
|
|
DetailMeshTimestamp++;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateResult()
|
|
{
|
|
|
|
if (bDetailMeshValid == false)
|
|
{
|
|
UpdateDetailMesh();
|
|
bDetailMeshValid = true;
|
|
}
|
|
|
|
if (bResultValid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// clear warning (ugh)
|
|
GetToolManager()->DisplayMessage(FText(), EToolMessageLevel::UserWarning);
|
|
|
|
int32 ImageSize = (int32)Settings->Resolution;
|
|
FImageDimensions Dimensions(ImageSize, ImageSize);
|
|
|
|
FBakeCacheSettings BakeCacheSettings;
|
|
BakeCacheSettings.Dimensions = Dimensions;
|
|
BakeCacheSettings.UVLayer = FCString::Atoi(*Settings->UVLayer);
|
|
BakeCacheSettings.DetailTimestamp = this->DetailMeshTimestamp;
|
|
|
|
// rebuild bake cache if we need to
|
|
if (!(CachedBakeCacheSettings == BakeCacheSettings))
|
|
{
|
|
BakeCache = MakePimpl<FMeshImageBakingCache>();
|
|
BakeCache->SetDetailMesh(DetailMesh.Get(), DetailSpatial.Get());
|
|
BakeCache->SetBakeTargetMesh(&BaseMesh);
|
|
BakeCache->SetDimensions(Dimensions);
|
|
BakeCache->SetUVLayer(BakeCacheSettings.UVLayer);
|
|
BakeCache->ValidateCache();
|
|
}
|
|
|
|
// rebuild select map type
|
|
switch (Settings->MapType)
|
|
{
|
|
default:
|
|
case EBakeMapType::TangentSpaceNormalMap:
|
|
UpdateResult_Normal();
|
|
break;
|
|
case EBakeMapType::AmbientOcclusion:
|
|
UpdateResult_Occlusion();
|
|
break;
|
|
case EBakeMapType::Curvature:
|
|
UpdateResult_Curvature();
|
|
break;
|
|
|
|
case EBakeMapType::NormalImage:
|
|
case EBakeMapType::FaceNormalImage:
|
|
case EBakeMapType::PositionImage:
|
|
UpdateResult_MeshProperty();
|
|
break;
|
|
|
|
case EBakeMapType::Texture2DImage:
|
|
UpdateResult_Texture2DImage();
|
|
break;
|
|
}
|
|
|
|
|
|
UpdateVisualization();
|
|
GetToolManager()->PostInvalidation();
|
|
|
|
bResultValid = true;
|
|
}
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateResult_Normal()
|
|
{
|
|
check(BakeCache->IsCacheValid());
|
|
|
|
int32 ImageSize = (int32)Settings->Resolution;
|
|
FImageDimensions Dimensions(ImageSize, ImageSize);
|
|
|
|
FNormalMapSettings NormalMapSettings;
|
|
NormalMapSettings.Dimensions = Dimensions;
|
|
|
|
if (!(CachedNormalMapSettings == NormalMapSettings))
|
|
{
|
|
FMeshNormalMapBaker NormalBaker;
|
|
NormalBaker.SetCache(BakeCache.Get());
|
|
NormalBaker.BaseMeshTangents = BaseMeshTangents.Get();
|
|
NormalBaker.Bake();
|
|
|
|
FTexture2DBuilder TextureBuilder;
|
|
TextureBuilder.Initialize(FTexture2DBuilder::ETextureType::NormalMap, Dimensions);
|
|
TextureBuilder.Copy(*NormalBaker.GetResult());
|
|
TextureBuilder.Commit(false);
|
|
CachedNormalMap = TextureBuilder.GetTexture2D();
|
|
CachedNormalMapSettings = NormalMapSettings;
|
|
}
|
|
}
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateResult_Occlusion()
|
|
{
|
|
check(BakeCache->IsCacheValid());
|
|
|
|
int32 ImageSize = (int32)Settings->Resolution;
|
|
FImageDimensions Dimensions(ImageSize, ImageSize);
|
|
|
|
FOcclusionMapSettings OcclusionMapSettings;
|
|
OcclusionMapSettings.Dimensions = Dimensions;
|
|
OcclusionMapSettings.MaxDistance = (OcclusionMapProps->MaxDistance == 0) ? TNumericLimits<float>::Max() : OcclusionMapProps->MaxDistance;
|
|
OcclusionMapSettings.OcclusionRays = OcclusionMapProps->OcclusionRays;
|
|
OcclusionMapSettings.BlurRadius = (OcclusionMapProps->bGaussianBlur) ? OcclusionMapProps->BlurRadius : 0.0;
|
|
OcclusionMapSettings.BiasAngle = OcclusionMapProps->BiasAngle;
|
|
|
|
if ( !(CachedOcclusionMapSettings == OcclusionMapSettings) )
|
|
{
|
|
FMeshOcclusionMapBaker OcclusionBaker;
|
|
OcclusionBaker.SetCache(BakeCache.Get());
|
|
OcclusionBaker.NumOcclusionRays = OcclusionMapSettings.OcclusionRays;
|
|
OcclusionBaker.BlurRadius = OcclusionMapSettings.BlurRadius;
|
|
OcclusionBaker.BiasAngleDeg = OcclusionMapSettings.BiasAngle;
|
|
OcclusionBaker.MaxDistance = OcclusionMapSettings.MaxDistance;
|
|
OcclusionBaker.Bake();
|
|
|
|
FTexture2DBuilder TextureBuilder;
|
|
TextureBuilder.Initialize(FTexture2DBuilder::ETextureType::AmbientOcclusion, Dimensions);
|
|
TextureBuilder.Copy(*OcclusionBaker.GetResult());
|
|
TextureBuilder.Commit(false);
|
|
CachedOcclusionMap = TextureBuilder.GetTexture2D();
|
|
CachedOcclusionMapSettings = OcclusionMapSettings;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateResult_Curvature()
|
|
{
|
|
check(BakeCache->IsCacheValid());
|
|
|
|
int32 ImageSize = (int32)Settings->Resolution;
|
|
FImageDimensions Dimensions(ImageSize, ImageSize);
|
|
|
|
FCurvatureMapSettings CurvatureMapSettings;
|
|
CurvatureMapSettings.Dimensions = Dimensions;
|
|
CurvatureMapSettings.RangeMultiplier = CurvatureMapProps->RangeMultiplier;
|
|
CurvatureMapSettings.MinRangeMultiplier = CurvatureMapProps->MinRangeMultiplier;
|
|
switch (CurvatureMapProps->CurvatureType)
|
|
{
|
|
default:
|
|
case EBakedCurvatureTypeMode::MeanAverage:
|
|
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapBaker::ECurvatureType::Mean;
|
|
break;
|
|
case EBakedCurvatureTypeMode::Gaussian:
|
|
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapBaker::ECurvatureType::Gaussian;
|
|
break;
|
|
case EBakedCurvatureTypeMode::Max:
|
|
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapBaker::ECurvatureType::MaxPrincipal;
|
|
break;
|
|
case EBakedCurvatureTypeMode::Min:
|
|
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapBaker::ECurvatureType::MinPrincipal;
|
|
break;
|
|
}
|
|
switch (CurvatureMapProps->ColorMode)
|
|
{
|
|
default:
|
|
case EBakedCurvatureColorMode::Grayscale:
|
|
CurvatureMapSettings.ColorMode = (int32)FMeshCurvatureMapBaker::EColorMode::BlackGrayWhite;
|
|
break;
|
|
case EBakedCurvatureColorMode::RedBlue:
|
|
CurvatureMapSettings.ColorMode = (int32)FMeshCurvatureMapBaker::EColorMode::RedBlue;
|
|
break;
|
|
case EBakedCurvatureColorMode::RedGreenBlue:
|
|
CurvatureMapSettings.ColorMode = (int32)FMeshCurvatureMapBaker::EColorMode::RedGreenBlue;
|
|
break;
|
|
}
|
|
switch (CurvatureMapProps->Clamping)
|
|
{
|
|
default:
|
|
case EBakedCurvatureClampMode::None:
|
|
CurvatureMapSettings.ClampMode = (int32)FMeshCurvatureMapBaker::EClampMode::FullRange;
|
|
break;
|
|
case EBakedCurvatureClampMode::Positive:
|
|
CurvatureMapSettings.ClampMode = (int32)FMeshCurvatureMapBaker::EClampMode::Positive;
|
|
break;
|
|
case EBakedCurvatureClampMode::Negative:
|
|
CurvatureMapSettings.ClampMode = (int32)FMeshCurvatureMapBaker::EClampMode::Negative;
|
|
break;
|
|
}
|
|
CurvatureMapSettings.BlurRadius = (CurvatureMapProps->bGaussianBlur) ? CurvatureMapProps->BlurRadius : 0.0;
|
|
|
|
if (!(CachedCurvatureMapSettings == CurvatureMapSettings))
|
|
{
|
|
FMeshCurvatureMapBaker CurvatureBaker;
|
|
CurvatureBaker.SetCache(BakeCache.Get());
|
|
CurvatureBaker.RangeScale = FMathd::Clamp(CurvatureMapSettings.RangeMultiplier, 0.0001, 1000.0);
|
|
CurvatureBaker.MinRangeScale = FMathd::Clamp(CurvatureMapSettings.MinRangeMultiplier, 0.0, 1.0);
|
|
CurvatureBaker.UseCurvatureType = (FMeshCurvatureMapBaker::ECurvatureType)CurvatureMapSettings.CurvatureType;
|
|
CurvatureBaker.UseColorMode = (FMeshCurvatureMapBaker::EColorMode)CurvatureMapSettings.ColorMode;
|
|
CurvatureBaker.UseClampMode = (FMeshCurvatureMapBaker::EClampMode)CurvatureMapSettings.ClampMode;
|
|
CurvatureBaker.BlurRadius = CurvatureMapSettings.BlurRadius;
|
|
CurvatureBaker.Bake();
|
|
|
|
FTexture2DBuilder TextureBuilder;
|
|
TextureBuilder.Initialize(FTexture2DBuilder::ETextureType::Color, Dimensions);
|
|
TextureBuilder.Copy(*CurvatureBaker.GetResult());
|
|
TextureBuilder.Commit(false);
|
|
CachedCurvatureMap = TextureBuilder.GetTexture2D();
|
|
CachedCurvatureMapSettings = CurvatureMapSettings;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateResult_MeshProperty()
|
|
{
|
|
check(BakeCache->IsCacheValid());
|
|
|
|
int32 ImageSize = (int32)Settings->Resolution;
|
|
FImageDimensions Dimensions(ImageSize, ImageSize);
|
|
|
|
FMeshPropertyMapSettings MeshPropertyMapSettings;
|
|
MeshPropertyMapSettings.Dimensions = Dimensions;
|
|
switch (Settings->MapType)
|
|
{
|
|
case EBakeMapType::NormalImage:
|
|
MeshPropertyMapSettings.PropertyTypeIndex = (int32)EMeshPropertyBakeType::Normal;
|
|
break;
|
|
case EBakeMapType::FaceNormalImage:
|
|
MeshPropertyMapSettings.PropertyTypeIndex = (int32)EMeshPropertyBakeType::FacetNormal;
|
|
break;
|
|
case EBakeMapType::PositionImage:
|
|
MeshPropertyMapSettings.PropertyTypeIndex = (int32)EMeshPropertyBakeType::Position;
|
|
break;
|
|
default:
|
|
check(false); // should not be possible!
|
|
}
|
|
//MeshPropertyMapSettings.BlurRadius = (CurvatureMapProps->bGaussianBlur) ? CurvatureMapProps->BlurRadius : 0.0;
|
|
|
|
if (!(CachedMeshPropertyMapSettings == MeshPropertyMapSettings))
|
|
{
|
|
FMeshPropertyMapBaker MeshPropertyBaker;
|
|
MeshPropertyBaker.SetCache(BakeCache.Get());
|
|
MeshPropertyBaker.Property = (EMeshPropertyBakeType)MeshPropertyMapSettings.PropertyTypeIndex;
|
|
//MeshPropertyBaker.BlurRadius = CurvatureMapSettings.BlurRadius;
|
|
MeshPropertyBaker.Bake();
|
|
|
|
FTexture2DBuilder TextureBuilder;
|
|
TextureBuilder.Initialize(FTexture2DBuilder::ETextureType::Color, Dimensions);
|
|
TextureBuilder.Copy(*MeshPropertyBaker.GetResult());
|
|
TextureBuilder.Commit(false);
|
|
CachedMeshPropertyMap = TextureBuilder.GetTexture2D();
|
|
CachedMeshPropertyMapSettings = MeshPropertyMapSettings;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FTempTextureAccess
|
|
{
|
|
public:
|
|
FTempTextureAccess(UTexture2D* DisplacementMap)
|
|
: DisplacementMap(DisplacementMap)
|
|
{
|
|
check(DisplacementMap);
|
|
OldCompressionSettings = DisplacementMap->CompressionSettings;
|
|
bOldSRGB = DisplacementMap->SRGB;
|
|
#if WITH_EDITOR
|
|
OldMipGenSettings = DisplacementMap->MipGenSettings;
|
|
#endif
|
|
DisplacementMap->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
|
|
DisplacementMap->SRGB = false;
|
|
#if WITH_EDITOR
|
|
DisplacementMap->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
|
|
#endif
|
|
DisplacementMap->UpdateResource();
|
|
|
|
FormattedImageData = reinterpret_cast<const FColor*>(DisplacementMap->PlatformData->Mips[0].BulkData.LockReadOnly());
|
|
}
|
|
FTempTextureAccess(const FTempTextureAccess&) = delete;
|
|
FTempTextureAccess(FTempTextureAccess&&) = delete;
|
|
void operator=(const FTempTextureAccess&) = delete;
|
|
void operator=(FTempTextureAccess&&) = delete;
|
|
|
|
~FTempTextureAccess()
|
|
{
|
|
DisplacementMap->PlatformData->Mips[0].BulkData.Unlock();
|
|
|
|
DisplacementMap->CompressionSettings = OldCompressionSettings;
|
|
DisplacementMap->SRGB = bOldSRGB;
|
|
#if WITH_EDITOR
|
|
DisplacementMap->MipGenSettings = OldMipGenSettings;
|
|
#endif
|
|
|
|
DisplacementMap->UpdateResource();
|
|
}
|
|
|
|
bool HasData() const
|
|
{
|
|
return FormattedImageData != nullptr;
|
|
}
|
|
const FColor* GetData() const
|
|
{
|
|
return FormattedImageData;
|
|
}
|
|
|
|
FImageDimensions GetDimensions() const
|
|
{
|
|
int32 Width = DisplacementMap->PlatformData->Mips[0].SizeX;
|
|
int32 Height = DisplacementMap->PlatformData->Mips[0].SizeY;
|
|
return FImageDimensions(Width, Height);
|
|
}
|
|
|
|
|
|
bool CopyTo(TImageBuilder<FVector4f>& DestImage) const
|
|
{
|
|
if (!HasData()) return false;
|
|
|
|
FImageDimensions TextureDimensions = GetDimensions();
|
|
if (ensure(DestImage.GetDimensions() == TextureDimensions) == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int64 Num = TextureDimensions.Num();
|
|
for (int32 i = 0; i < Num; ++i)
|
|
{
|
|
FColor ByteColor = FormattedImageData[i];
|
|
FLinearColor FloatColor(ByteColor);
|
|
DestImage.SetPixel(i, FVector4f(FloatColor));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
UTexture2D* DisplacementMap{ nullptr };
|
|
TextureCompressionSettings OldCompressionSettings{};
|
|
TextureMipGenSettings OldMipGenSettings{};
|
|
bool bOldSRGB{ false };
|
|
const FColor* FormattedImageData{ nullptr };
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateResult_Texture2DImage()
|
|
{
|
|
check(BakeCache->IsCacheValid());
|
|
|
|
int32 ImageSize = (int32)Settings->Resolution;
|
|
FImageDimensions Dimensions(ImageSize, ImageSize);
|
|
|
|
FTexture2DImageSettings NewSettings;
|
|
NewSettings.Dimensions = Dimensions;
|
|
NewSettings.UVLayer = 0;
|
|
|
|
const FDynamicMeshUVOverlay* UVOverlay = DetailMesh->Attributes()->GetUVLayer(NewSettings.UVLayer);
|
|
if (UVOverlay == nullptr)
|
|
{
|
|
GetToolManager()->DisplayMessage(LOCTEXT("InvalidUVWarning", "The Source Mesh does not have the selected UV layer"), EToolMessageLevel::UserWarning);
|
|
return;
|
|
}
|
|
|
|
if (Texture2DProps->SourceTexture == nullptr)
|
|
{
|
|
GetToolManager()->DisplayMessage(LOCTEXT("InvalidTextureWarning", "The Source Texture is not valid"), EToolMessageLevel::UserWarning);
|
|
return;
|
|
}
|
|
|
|
|
|
TImageBuilder<FVector4f> TextureImage;
|
|
{
|
|
FTempTextureAccess TextureAccess(Texture2DProps->SourceTexture);
|
|
TextureImage.SetDimensions(TextureAccess.GetDimensions());
|
|
if (!TextureAccess.CopyTo(TextureImage))
|
|
{
|
|
GetToolManager()->DisplayMessage(LOCTEXT("CannotReadTextureWarning", "Cannot read from the source texture"), EToolMessageLevel::UserWarning);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!(CachedTexture2DImageSettings == NewSettings))
|
|
{
|
|
FMeshResampleImageBaker Baker;
|
|
Baker.SetCache(BakeCache.Get());
|
|
Baker.DetailUVOverlay = UVOverlay;
|
|
Baker.SampleFunction = [&](FVector2d UVCoord) {
|
|
return TextureImage.BilinearSampleUV<float>(UVCoord, FVector4f(0,0,0,1));
|
|
};
|
|
Baker.Bake();
|
|
|
|
FTexture2DBuilder TextureBuilder;
|
|
TextureBuilder.Initialize(FTexture2DBuilder::ETextureType::Color, Dimensions);
|
|
TextureBuilder.Copy(*Baker.GetResult(), true);
|
|
TextureBuilder.Commit(false);
|
|
CachedTexture2DImageMap = TextureBuilder.GetTexture2D();
|
|
CachedTexture2DImageSettings = NewSettings;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateVisualization()
|
|
{
|
|
switch (Settings->MapType)
|
|
{
|
|
default:
|
|
Settings->Result = nullptr;
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("NormalMap"), EmptyNormalMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("OcclusionMap"), EmptyColorMapWhite);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("ColorMap"), EmptyColorMapWhite);
|
|
break;
|
|
case EBakeMapType::TangentSpaceNormalMap:
|
|
Settings->Result = CachedNormalMap;
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("NormalMap"), CachedNormalMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("OcclusionMap"), EmptyColorMapWhite);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("ColorMap"), EmptyColorMapWhite);
|
|
break;
|
|
case EBakeMapType::AmbientOcclusion:
|
|
Settings->Result = CachedOcclusionMap;
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("NormalMap"), EmptyNormalMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("OcclusionMap"), CachedOcclusionMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("ColorMap"), EmptyColorMapWhite);
|
|
break;
|
|
case EBakeMapType::Curvature:
|
|
Settings->Result = CachedCurvatureMap;
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("NormalMap"), EmptyNormalMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("OcclusionMap"), EmptyColorMapWhite);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("ColorMap"), CachedCurvatureMap);
|
|
break;
|
|
|
|
case EBakeMapType::NormalImage:
|
|
case EBakeMapType::FaceNormalImage:
|
|
case EBakeMapType::PositionImage:
|
|
Settings->Result = CachedMeshPropertyMap;
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("NormalMap"), EmptyNormalMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("OcclusionMap"), EmptyColorMapWhite);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("ColorMap"), CachedMeshPropertyMap);
|
|
break;
|
|
|
|
case EBakeMapType::Texture2DImage:
|
|
Settings->Result = CachedTexture2DImageMap;
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("NormalMap"), EmptyNormalMap);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("OcclusionMap"), EmptyColorMapWhite);
|
|
PreviewMaterial->SetTextureParameterValue(TEXT("ColorMap"), CachedTexture2DImageMap);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::UpdateOnModeChange()
|
|
{
|
|
SetToolPropertySourceEnabled(NormalMapProps, false);
|
|
SetToolPropertySourceEnabled(OcclusionMapProps, false);
|
|
SetToolPropertySourceEnabled(CurvatureMapProps, false);
|
|
SetToolPropertySourceEnabled(Texture2DProps, false);
|
|
|
|
switch (Settings->MapType)
|
|
{
|
|
case EBakeMapType::TangentSpaceNormalMap:
|
|
SetToolPropertySourceEnabled(NormalMapProps, true);
|
|
break;
|
|
case EBakeMapType::AmbientOcclusion:
|
|
SetToolPropertySourceEnabled(OcclusionMapProps, true);
|
|
break;
|
|
case EBakeMapType::Curvature:
|
|
SetToolPropertySourceEnabled(CurvatureMapProps, true);
|
|
break;
|
|
case EBakeMapType::Texture2DImage:
|
|
SetToolPropertySourceEnabled(Texture2DProps, true);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UBakeMeshAttributeMapsTool::InitializeEmptyMaps()
|
|
{
|
|
FTexture2DBuilder NormalsBuilder;
|
|
NormalsBuilder.Initialize(FTexture2DBuilder::ETextureType::NormalMap, FImageDimensions(16, 16));
|
|
NormalsBuilder.Commit(false);
|
|
EmptyNormalMap = NormalsBuilder.GetTexture2D();
|
|
|
|
FTexture2DBuilder ColorBuilderBlack;
|
|
ColorBuilderBlack.Initialize(FTexture2DBuilder::ETextureType::Color, FImageDimensions(16, 16));
|
|
ColorBuilderBlack.Clear(FColor(0,0,0));
|
|
ColorBuilderBlack.Commit(false);
|
|
EmptyColorMapBlack = ColorBuilderBlack.GetTexture2D();
|
|
|
|
FTexture2DBuilder ColorBuilderWhite;
|
|
ColorBuilderWhite.Initialize(FTexture2DBuilder::ETextureType::Color, FImageDimensions(16, 16));
|
|
ColorBuilderWhite.Clear(FColor::White);
|
|
ColorBuilderWhite.Commit(false);
|
|
EmptyColorMapWhite = ColorBuilderWhite.GetTexture2D();
|
|
}
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|