Files
UnrealEngineUWP/Engine/Plugins/Experimental/MeshModelingToolsetExp/Source/MeshModelingToolsExp/Private/BakeMeshAttributeTool.cpp
matija kecman dfe144b82b Render Capture Baking: Remove sub-classing of BakeRC from UBakeMeshAttributeMapsToolBase and implement a few fixes
Fixed materials in the BakeRC tool missing UV layer switches or controls for brightness of the Base Color, Subsurface Color or Emissive channels
Removed the unused AO Multiplier setting that appeared in the Preview panel of the tool UI
Improved performance of BakeRC tool baking step by not recomputing the target mesh spatial index and uv charts
Improved the clarity of the analytics code since the sub-classing has enabled us to more easily use custom BakeRC analytics


#rb lonnie.li
#rnx
#preflight 63cfaa1ed83c1837b182104b
#jira none

[CL 23828120 by matija kecman in ue5-main branch]
2023-01-24 05:18:59 -05:00

348 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BakeMeshAttributeTool.h"
#include "InteractiveToolManager.h"
#include "ModelingToolTargetUtil.h"
#include "ToolSetupUtil.h"
#include "AssetUtils/Texture2DUtil.h"
#include "Sampling/MeshCurvatureMapEvaluator.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(BakeMeshAttributeTool)
using namespace UE::Geometry;
#define LOCTEXT_NAMESPACE "UBakeMeshAttributeTool"
void UBakeMeshAttributeTool::Setup()
{
Super::Setup();
// Setup preview materials
WorkingPreviewMaterial = ToolSetupUtil::GetDefaultWorkingMaterialInstance(GetToolManager());
ErrorPreviewMaterial = ToolSetupUtil::GetDefaultErrorMaterial(GetToolManager());
}
bool UBakeMeshAttributeTool::ValidTargetMeshTangents()
{
if (bCheckTargetMeshTangents)
{
bValidTargetMeshTangents = TargetMeshTangents ? FDynamicMeshTangents(&TargetMesh).HasValidTangents(true) : false;
bCheckTargetMeshTangents = false;
}
return bValidTargetMeshTangents;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_TargetMeshTangents(EBakeMapType BakeType)
{
EBakeOpState ResultState = EBakeOpState::Clean;
const bool bNeedTargetMeshTangents = (bool)(BakeType & (EBakeMapType::TangentSpaceNormal | EBakeMapType::BentNormal));
if (bNeedTargetMeshTangents && !ValidTargetMeshTangents())
{
GetToolManager()->DisplayMessage(LOCTEXT("InvalidTargetTangentsWarning", "The Target Mesh does not have valid tangents."), EToolMessageLevel::UserWarning);
ResultState = EBakeOpState::Invalid;
}
return ResultState;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_Normal(const FImageDimensions& Dimensions)
{
EBakeOpState ResultState = EBakeOpState::Clean;
FNormalMapSettings NormalMapSettings;
NormalMapSettings.Dimensions = Dimensions;
if (!(CachedNormalMapSettings == NormalMapSettings))
{
CachedNormalMapSettings = NormalMapSettings;
ResultState = EBakeOpState::Evaluate;
}
return ResultState;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_Occlusion(const FImageDimensions& Dimensions)
{
EBakeOpState ResultState = EBakeOpState::Clean;
if (!OcclusionSettings)
{
return EBakeOpState::Invalid;
}
FOcclusionMapSettings OcclusionMapSettings;
OcclusionMapSettings.Dimensions = Dimensions;
OcclusionMapSettings.MaxDistance = (OcclusionSettings->MaxDistance == 0) ? TNumericLimits<float>::Max() : OcclusionSettings->MaxDistance;
OcclusionMapSettings.OcclusionRays = OcclusionSettings->OcclusionRays;
OcclusionMapSettings.SpreadAngle = OcclusionSettings->SpreadAngle;
OcclusionMapSettings.BiasAngle = OcclusionSettings->BiasAngle;
if ( !(CachedOcclusionMapSettings == OcclusionMapSettings) )
{
CachedOcclusionMapSettings = OcclusionMapSettings;
ResultState = EBakeOpState::Evaluate;
}
return ResultState;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_Curvature(const FImageDimensions& Dimensions)
{
EBakeOpState ResultState = EBakeOpState::Clean;
if (!CurvatureSettings)
{
return EBakeOpState::Invalid;
}
FCurvatureMapSettings CurvatureMapSettings;
CurvatureMapSettings.Dimensions = Dimensions;
CurvatureMapSettings.RangeMultiplier = CurvatureSettings->ColorRangeMultiplier;
CurvatureMapSettings.MinRangeMultiplier = CurvatureSettings->MinRangeMultiplier;
switch (CurvatureSettings->CurvatureType)
{
default:
case EBakeCurvatureTypeMode::MeanAverage:
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapEvaluator::ECurvatureType::Mean;
break;
case EBakeCurvatureTypeMode::Gaussian:
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapEvaluator::ECurvatureType::Gaussian;
break;
case EBakeCurvatureTypeMode::Max:
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapEvaluator::ECurvatureType::MaxPrincipal;
break;
case EBakeCurvatureTypeMode::Min:
CurvatureMapSettings.CurvatureType = (int32)FMeshCurvatureMapEvaluator::ECurvatureType::MinPrincipal;
break;
}
switch (CurvatureSettings->ColorMapping)
{
default:
case EBakeCurvatureColorMode::Grayscale:
CurvatureMapSettings.ColorMode = (int32)FMeshCurvatureMapEvaluator::EColorMode::BlackGrayWhite;
break;
case EBakeCurvatureColorMode::RedBlue:
CurvatureMapSettings.ColorMode = (int32)FMeshCurvatureMapEvaluator::EColorMode::RedBlue;
break;
case EBakeCurvatureColorMode::RedGreenBlue:
CurvatureMapSettings.ColorMode = (int32)FMeshCurvatureMapEvaluator::EColorMode::RedGreenBlue;
break;
}
switch (CurvatureSettings->Clamping)
{
default:
case EBakeCurvatureClampMode::None:
CurvatureMapSettings.ClampMode = (int32)FMeshCurvatureMapEvaluator::EClampMode::FullRange;
break;
case EBakeCurvatureClampMode::OnlyPositive:
CurvatureMapSettings.ClampMode = (int32)FMeshCurvatureMapEvaluator::EClampMode::Positive;
break;
case EBakeCurvatureClampMode::OnlyNegative:
CurvatureMapSettings.ClampMode = (int32)FMeshCurvatureMapEvaluator::EClampMode::Negative;
break;
}
if (!(CachedCurvatureMapSettings == CurvatureMapSettings))
{
CachedCurvatureMapSettings = CurvatureMapSettings;
ResultState = EBakeOpState::Evaluate;
}
return ResultState;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_MeshProperty(const FImageDimensions& Dimensions)
{
EBakeOpState ResultState = EBakeOpState::Clean;
FMeshPropertyMapSettings MeshPropertyMapSettings;
MeshPropertyMapSettings.Dimensions = Dimensions;
if (!(CachedMeshPropertyMapSettings == MeshPropertyMapSettings))
{
CachedMeshPropertyMapSettings = MeshPropertyMapSettings;
ResultState = EBakeOpState::Evaluate;
}
return ResultState;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_Texture2DImage(const FImageDimensions& Dimensions, const FDynamicMesh3* DetailMesh)
{
EBakeOpState ResultState = EBakeOpState::Clean;
if (!TextureSettings || !DetailMesh)
{
return EBakeOpState::Invalid;
}
FTexture2DSettings NewSettings;
NewSettings.Dimensions = Dimensions;
NewSettings.UVLayer = TextureSettings->UVLayerNamesList.IndexOfByKey(TextureSettings->UVLayer);
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 EBakeOpState::Invalid;
}
if (TextureSettings->SourceTexture == nullptr)
{
GetToolManager()->DisplayMessage(LOCTEXT("InvalidTextureWarning", "The Source Texture is not valid"), EToolMessageLevel::UserWarning);
return EBakeOpState::Invalid;
}
{
CachedTextureImage = MakeShared<UE::Geometry::TImageBuilder<FVector4f>, ESPMode::ThreadSafe>();
if (!UE::AssetUtils::ReadTexture(TextureSettings->SourceTexture, *CachedTextureImage, bPreferPlatformData))
{
GetToolManager()->DisplayMessage(LOCTEXT("CannotReadTextureWarning", "Cannot read from the source texture"), EToolMessageLevel::UserWarning);
return EBakeOpState::Invalid;
}
}
if (!(CachedTexture2DSettings == NewSettings))
{
CachedTexture2DSettings = NewSettings;
ResultState = EBakeOpState::Evaluate;
}
return ResultState;
}
EBakeOpState UBakeMeshAttributeTool::UpdateResult_MultiTexture(const FImageDimensions& Dimensions, const FDynamicMesh3* DetailMesh)
{
EBakeOpState ResultState = EBakeOpState::Clean;
if (!MultiTextureSettings || !DetailMesh)
{
return EBakeOpState::Invalid;
}
FTexture2DSettings NewSettings;
NewSettings.Dimensions = Dimensions;
NewSettings.UVLayer = MultiTextureSettings->UVLayerNamesList.IndexOfByKey(MultiTextureSettings->UVLayer);
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 EBakeOpState::Invalid;
}
const int NumMaterialIDs = MultiTextureSettings->MaterialIDSourceTextures.Num();
CachedMultiTextures.Reset();
CachedMultiTextures.SetNum(NumMaterialIDs);
int NumValidTextures = 0;
for ( int MaterialID = 0; MaterialID < NumMaterialIDs; ++MaterialID)
{
if (UTexture2D* Texture = MultiTextureSettings->MaterialIDSourceTextures[MaterialID])
{
CachedMultiTextures[MaterialID] = MakeShared<TImageBuilder<FVector4f>, ESPMode::ThreadSafe>();
if (!UE::AssetUtils::ReadTexture(Texture, *CachedMultiTextures[MaterialID], bPreferPlatformData))
{
GetToolManager()->DisplayMessage(LOCTEXT("CannotReadTextureWarning", "Cannot read from the source texture"), EToolMessageLevel::UserWarning);
return EBakeOpState::Invalid;
}
++NumValidTextures;
}
}
if (NumValidTextures == 0)
{
GetToolManager()->DisplayMessage(LOCTEXT("InvalidTextureWarning", "The Source Texture is not valid"), EToolMessageLevel::UserWarning);
return EBakeOpState::Invalid;
}
if (!(CachedMultiTexture2DSettings == NewSettings))
{
CachedMultiTexture2DSettings = NewSettings;
ResultState = EBakeOpState::Evaluate;
}
return ResultState;
}
int UBakeMeshAttributeTool::SelectColorTextureToBake(const TArray<UTexture*>& Textures)
{
TArray<int> TextureVotes;
TextureVotes.Init(0, Textures.Num());
for (int TextureIndex = 0; TextureIndex < Textures.Num(); ++TextureIndex)
{
UTexture* Tex = Textures[TextureIndex];
UTexture2D* Tex2D = Cast<UTexture2D>(Tex);
if (Tex2D)
{
// Texture uses SRGB
if (Tex->SRGB != 0)
{
++TextureVotes[TextureIndex];
}
#if WITH_EDITORONLY_DATA
// Texture has multiple channels
ETextureSourceFormat Format = Tex->Source.GetFormat();
if (Format == TSF_BGRA8 || Format == TSF_BGRE8 || Format == TSF_RGBA16 || Format == TSF_RGBA16F || Format == TSF_RGBA32F)
{
++TextureVotes[TextureIndex];
}
#endif
// What else? Largest texture? Most layers? Most mipmaps?
}
}
int MaxIndex = -1;
int MaxVotes = -1;
for (int TextureIndex = 0; TextureIndex < Textures.Num(); ++TextureIndex)
{
if (TextureVotes[TextureIndex] > MaxVotes)
{
MaxIndex = TextureIndex;
MaxVotes = TextureVotes[TextureIndex];
}
}
return MaxIndex;
}
void UBakeMeshAttributeTool::UpdateMultiTextureMaterialIDs(
UToolTarget* Target,
TArray<TObjectPtr<UTexture2D>>& AllSourceTextures,
TArray<TObjectPtr<UTexture2D>>& MaterialIDTextures)
{
ProcessComponentTextures(UE::ToolTarget::GetTargetComponent(Target),
[&AllSourceTextures, &MaterialIDTextures](const int NumMaterials, const int MaterialID, const TArray<UTexture*>& Textures)
{
MaterialIDTextures.SetNumZeroed(NumMaterials);
for (UTexture* Tex : Textures)
{
UTexture2D* Tex2D = Cast<UTexture2D>(Tex);
if (Tex2D)
{
AllSourceTextures.Add(Tex2D);
}
}
UTexture2D* Tex2D = nullptr;
constexpr bool bGuessAtTextures = true;
if constexpr (bGuessAtTextures)
{
const int SelectedTextureIndex = SelectColorTextureToBake(Textures);
if (SelectedTextureIndex >= 0)
{
Tex2D = Cast<UTexture2D>(Textures[SelectedTextureIndex]);
}
}
MaterialIDTextures[MaterialID] = Tex2D;
});
}
#undef LOCTEXT_NAMESPACE