2020-06-23 18:40:00 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "BakeMeshAttributeMapsTool.h"
# include "InteractiveToolManager.h"
# include "ToolBuilderUtil.h"
2021-06-13 00:35:22 -04:00
# include "DynamicMesh/DynamicMesh3.h"
# include "DynamicMesh/DynamicMeshAttributeSet.h"
# include "DynamicMesh/MeshTransforms.h"
2020-06-23 18:40:00 -04:00
# include "MeshDescriptionToDynamicMesh.h"
2021-05-26 17:14:57 -04:00
# include "Sampling/MeshNormalMapEvaluator.h"
# include "Sampling/MeshOcclusionMapEvaluator.h"
# include "Sampling/MeshCurvatureMapEvaluator.h"
# include "Sampling/MeshPropertyMapEvaluator.h"
# include "Sampling/MeshResampleImageEvaluator.h"
2020-06-23 18:40:00 -04:00
# include "Util/IndexUtil.h"
2021-06-12 14:28:52 -04:00
# include "Components/DynamicMeshComponent.h"
2020-06-23 18:40:00 -04:00
# include "Materials/Material.h"
# include "Materials/MaterialInstanceDynamic.h"
# include "ImageUtils.h"
# include "AssetUtils/Texture2DBuilder.h"
2021-06-02 15:58:00 -04:00
# include "ModelingObjectsCreationAPI.h"
2020-06-23 18:40:00 -04:00
2021-02-23 18:03:26 -04:00
# include "TargetInterfaces/MaterialProvider.h"
# include "TargetInterfaces/MeshDescriptionProvider.h"
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
# include "TargetInterfaces/StaticMeshBackedTarget.h"
# include "ToolTargetManager.h"
2021-06-11 22:39:18 -04:00
# include "ModelingToolTargetUtil.h"
2021-02-23 18:03:26 -04:00
2020-08-11 01:36:57 -04:00
// required to pass UStaticMesh asset so we can save at same location
# include "Engine/Classes/Components/StaticMeshComponent.h"
# include "Engine/Classes/Engine/StaticMesh.h"
2021-03-09 19:33:56 -04:00
# include "ExplicitUseGeometryMathTypes.h" // using UE::Geometry::(math types)
using namespace UE : : Geometry ;
2020-06-23 18:40:00 -04:00
2021-03-09 19:33:56 -04:00
# define LOCTEXT_NAMESPACE "UBakeMeshAttributeMapsTool"
2020-06-23 18:40:00 -04:00
2021-06-03 15:29:38 -04:00
/*
* Static init
*/
// Only include the Occlusion bitmask rather than its components
// (AmbientOcclusion | BentNormal). Since the Occlusion baker can
// bake both types in a single pass, only iterating over the Occlusion
// bitmask gives direct access to both types without the need to
// externally track if we've handled the Occlusion evaluator in a prior
// iteration loop.
static constexpr EBakeMapType ALL_BAKE_MAP_TYPES [ ] =
{
EBakeMapType : : TangentSpaceNormalMap ,
EBakeMapType : : Occlusion , // (AmbientOcclusion | BentNormal)
EBakeMapType : : Curvature ,
EBakeMapType : : Texture2DImage ,
EBakeMapType : : NormalImage ,
EBakeMapType : : FaceNormalImage ,
EBakeMapType : : PositionImage ,
EBakeMapType : : MaterialID ,
EBakeMapType : : MultiTexture
} ;
2020-06-23 18:40:00 -04:00
/*
* ToolBuilder
*/
2021-02-23 18:03:26 -04:00
const FToolTargetTypeRequirements & UBakeMeshAttributeMapsToolBuilder : : GetTargetRequirements ( ) const
{
static FToolTargetTypeRequirements TypeRequirements ( {
UMeshDescriptionProvider : : StaticClass ( ) ,
UPrimitiveComponentBackedTarget : : StaticClass ( ) ,
UStaticMeshBackedTarget : : StaticClass ( ) , // currently only supports StaticMesh targets
UMaterialProvider : : StaticClass ( )
} ) ;
return TypeRequirements ;
}
2020-06-23 18:40:00 -04:00
bool UBakeMeshAttributeMapsToolBuilder : : CanBuildTool ( const FToolBuilderState & SceneState ) const
{
2021-02-23 18:03:26 -04:00
int32 NumTargets = SceneState . TargetManager - > CountSelectedAndTargetable ( SceneState , GetTargetRequirements ( ) ) ;
return ( NumTargets = = 1 | | NumTargets = = 2 ) ;
2020-06-23 18:40:00 -04:00
}
UInteractiveTool * UBakeMeshAttributeMapsToolBuilder : : BuildTool ( const FToolBuilderState & SceneState ) const
{
UBakeMeshAttributeMapsTool * NewTool = NewObject < UBakeMeshAttributeMapsTool > ( SceneState . ToolManager ) ;
2021-02-23 18:03:26 -04:00
TArray < TObjectPtr < UToolTarget > > Targets = SceneState . TargetManager - > BuildAllSelectedTargetable ( SceneState , GetTargetRequirements ( ) ) ;
NewTool - > SetTargets ( MoveTemp ( Targets ) ) ;
2020-06-23 18:40:00 -04:00
return NewTool ;
}
2020-09-01 14:07:48 -04:00
TArray < FString > UBakeMeshAttributeMapsToolProperties : : GetUVLayerNamesFunc ( )
{
return UVLayerNamesList ;
}
2021-04-12 17:10:46 -04:00
/*
* Operators
*/
2020-09-01 14:07:48 -04:00
2021-06-03 15:29:38 -04:00
class FMeshMapBakerOp : public TGenericDataOperator < FMeshMapBaker >
2021-04-12 17:10:46 -04:00
{
public :
2021-06-03 15:29:38 -04:00
// General bake settings
2021-05-17 16:01:01 -04:00
TSharedPtr < UE : : Geometry : : FDynamicMesh3 , ESPMode : : ThreadSafe > DetailMesh ;
TSharedPtr < UE : : Geometry : : FDynamicMeshAABBTree3 , ESPMode : : ThreadSafe > DetailSpatial ;
UE : : Geometry : : FDynamicMesh3 * BaseMesh ;
TUniquePtr < UE : : Geometry : : FMeshMapBaker > Baker ;
UBakeMeshAttributeMapsTool : : FBakeCacheSettings BakeCacheSettings ;
2021-06-03 15:29:38 -04:00
TSharedPtr < UE : : Geometry : : TMeshTangents < double > , ESPMode : : ThreadSafe > BaseMeshTangents ;
2021-05-17 16:01:01 -04:00
2021-06-03 15:29:38 -04:00
// Map Type settings
EBakeMapType Maps ;
UBakeMeshAttributeMapsTool : : FNormalMapSettings NormalSettings ;
UBakeMeshAttributeMapsTool : : FOcclusionMapSettings OcclusionSettings ;
UBakeMeshAttributeMapsTool : : FCurvatureMapSettings CurvatureSettings ;
UBakeMeshAttributeMapsTool : : FMeshPropertyMapSettings PropertySettings ;
UBakeMeshAttributeMapsTool : : FTexture2DImageSettings TextureSettings ;
// Texture2DImage & MultiTexture settings
using ImagePtr = TSharedPtr < UE : : Geometry : : TImageBuilder < FVector4f > , ESPMode : : ThreadSafe > ;
const FDynamicMeshUVOverlay * UVOverlay = nullptr ;
ImagePtr TextureImage ;
TMap < int32 , ImagePtr > MaterialToTextureImageMap ;
// Begin TGenericDataOperator interface
2021-04-12 17:10:46 -04:00
virtual void CalculateResult ( FProgressCancel * Progress ) override
{
2021-05-17 16:01:01 -04:00
Baker = MakeUnique < FMeshMapBaker > ( ) ;
Baker - > CancelF = [ Progress ] ( ) {
2021-04-12 17:10:46 -04:00
return Progress & & Progress - > Cancelled ( ) ;
} ;
2021-05-17 16:01:01 -04:00
Baker - > SetTargetMesh ( BaseMesh ) ;
Baker - > SetDetailMesh ( DetailMesh . Get ( ) , DetailSpatial . Get ( ) ) ;
Baker - > SetDimensions ( BakeCacheSettings . Dimensions ) ;
Baker - > SetUVLayer ( BakeCacheSettings . UVLayer ) ;
Baker - > SetThickness ( BakeCacheSettings . Thickness ) ;
Baker - > SetMultisampling ( BakeCacheSettings . Multisampling ) ;
Baker - > SetTargetMeshTangents ( BaseMeshTangents ) ;
2021-06-03 15:29:38 -04:00
for ( const EBakeMapType MapType : ALL_BAKE_MAP_TYPES )
{
switch ( BakeCacheSettings . BakeMapTypes & MapType )
{
case EBakeMapType : : TangentSpaceNormalMap :
{
TSharedPtr < FMeshNormalMapEvaluator , ESPMode : : ThreadSafe > NormalEval = MakeShared < FMeshNormalMapEvaluator , ESPMode : : ThreadSafe > ( ) ;
Baker - > AddBaker ( NormalEval ) ;
break ;
}
case EBakeMapType : : AmbientOcclusion :
case EBakeMapType : : BentNormal :
case EBakeMapType : : Occlusion :
{
TSharedPtr < FMeshOcclusionMapEvaluator > OcclusionEval = MakeShared < FMeshOcclusionMapEvaluator > ( ) ;
OcclusionEval - > OcclusionType = EMeshOcclusionMapType : : None ;
if ( ( bool ) ( BakeCacheSettings . BakeMapTypes & EBakeMapType : : AmbientOcclusion ) )
{
OcclusionEval - > OcclusionType | = EMeshOcclusionMapType : : AmbientOcclusion ;
}
if ( ( bool ) ( BakeCacheSettings . BakeMapTypes & EBakeMapType : : BentNormal ) )
{
OcclusionEval - > OcclusionType | = EMeshOcclusionMapType : : BentNormal ;
}
OcclusionEval - > NumOcclusionRays = OcclusionSettings . OcclusionRays ;
OcclusionEval - > MaxDistance = OcclusionSettings . MaxDistance ;
OcclusionEval - > SpreadAngle = OcclusionSettings . SpreadAngle ;
OcclusionEval - > BiasAngleDeg = OcclusionSettings . BiasAngle ;
switch ( OcclusionSettings . Distribution )
{
case EOcclusionMapDistribution : : Cosine :
OcclusionEval - > Distribution = FMeshOcclusionMapEvaluator : : EDistribution : : Cosine ;
break ;
case EOcclusionMapDistribution : : Uniform :
OcclusionEval - > Distribution = FMeshOcclusionMapEvaluator : : EDistribution : : Uniform ;
break ;
}
switch ( OcclusionSettings . NormalSpace )
{
case ENormalMapSpace : : Tangent :
OcclusionEval - > NormalSpace = FMeshOcclusionMapEvaluator : : ESpace : : Tangent ;
break ;
case ENormalMapSpace : : Object :
OcclusionEval - > NormalSpace = FMeshOcclusionMapEvaluator : : ESpace : : Object ;
break ;
}
Baker - > AddBaker ( OcclusionEval ) ;
break ;
}
case EBakeMapType : : Curvature :
{
TSharedPtr < FMeshCurvatureMapEvaluator , ESPMode : : ThreadSafe > CurvatureBaker = MakeShared < FMeshCurvatureMapEvaluator , ESPMode : : ThreadSafe > ( ) ;
CurvatureBaker - > RangeScale = FMathd : : Clamp ( CurvatureSettings . RangeMultiplier , 0.0001 , 1000.0 ) ;
CurvatureBaker - > MinRangeScale = FMathd : : Clamp ( CurvatureSettings . MinRangeMultiplier , 0.0 , 1.0 ) ;
CurvatureBaker - > UseCurvatureType = ( FMeshCurvatureMapEvaluator : : ECurvatureType ) CurvatureSettings . CurvatureType ;
CurvatureBaker - > UseColorMode = ( FMeshCurvatureMapEvaluator : : EColorMode ) CurvatureSettings . ColorMode ;
CurvatureBaker - > UseClampMode = ( FMeshCurvatureMapEvaluator : : EClampMode ) CurvatureSettings . ClampMode ;
Baker - > AddBaker ( CurvatureBaker ) ;
break ;
}
case EBakeMapType : : NormalImage :
{
TSharedPtr < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > PropertyBaker = MakeShared < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > ( ) ;
PropertyBaker - > Property = EMeshPropertyMapType : : Normal ;
Baker - > AddBaker ( PropertyBaker ) ;
break ;
}
case EBakeMapType : : FaceNormalImage :
{
TSharedPtr < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > PropertyBaker = MakeShared < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > ( ) ;
PropertyBaker - > Property = EMeshPropertyMapType : : FacetNormal ;
Baker - > AddBaker ( PropertyBaker ) ;
break ;
}
case EBakeMapType : : PositionImage :
{
TSharedPtr < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > PropertyBaker = MakeShared < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > ( ) ;
PropertyBaker - > Property = EMeshPropertyMapType : : Position ;
Baker - > AddBaker ( PropertyBaker ) ;
break ;
}
case EBakeMapType : : MaterialID :
{
TSharedPtr < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > PropertyBaker = MakeShared < FMeshPropertyMapEvaluator , ESPMode : : ThreadSafe > ( ) ;
PropertyBaker - > Property = EMeshPropertyMapType : : MaterialID ;
Baker - > AddBaker ( PropertyBaker ) ;
break ;
}
case EBakeMapType : : Texture2DImage :
{
TSharedPtr < FMeshResampleImageEvaluator , ESPMode : : ThreadSafe > ResampleBaker = MakeShared < FMeshResampleImageEvaluator , ESPMode : : ThreadSafe > ( ) ;
ResampleBaker - > DetailUVOverlay = UVOverlay ;
ResampleBaker - > SampleFunction = [ this ] ( FVector2d UVCoord ) {
return TextureImage - > BilinearSampleUV < float > ( UVCoord , FVector4f ( 0 , 0 , 0 , 1 ) ) ;
} ;
Baker - > AddBaker ( ResampleBaker ) ;
break ;
}
case EBakeMapType : : MultiTexture :
{
TSharedPtr < FMeshMultiResampleImageEvaluator , ESPMode : : ThreadSafe > TextureBaker = MakeShared < FMeshMultiResampleImageEvaluator , ESPMode : : ThreadSafe > ( ) ;
TextureBaker - > DetailUVOverlay = UVOverlay ;
TextureBaker - > MultiTextures = MaterialToTextureImageMap ;
Baker - > AddBaker ( TextureBaker ) ;
break ;
}
default :
break ;
}
}
2021-04-12 17:10:46 -04:00
Baker - > Bake ( ) ;
SetResult ( MoveTemp ( Baker ) ) ;
}
2021-06-03 15:29:38 -04:00
// End TGenericDataOperator interface
2021-04-30 17:04:37 -04:00
} ;
2020-06-23 18:40:00 -04:00
/*
* Tool
*/
void UBakeMeshAttributeMapsTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
// create dynamic mesh component to use for live preview
2021-06-11 22:39:18 -04:00
// TODO: convert to UPreviewMesh
AActor * ParentActor = UE : : ToolTarget : : GetTargetActor ( Targets [ 0 ] ) ;
2021-06-12 14:28:52 -04:00
DynamicMeshComponent = NewObject < UDynamicMeshComponent > ( ParentActor ) ;
2021-06-11 22:39:18 -04:00
DynamicMeshComponent - > SetupAttachment ( ParentActor - > GetRootComponent ( ) ) ;
2020-06-23 18:40:00 -04:00
DynamicMeshComponent - > RegisterComponent ( ) ;
2021-06-11 22:39:18 -04:00
DynamicMeshComponent - > SetWorldTransform ( ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ) ;
2020-06-23 18:40:00 -04:00
// transfer materials
2021-06-11 22:39:18 -04:00
FComponentMaterialSet MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ 0 ] ) ;
2020-06-23 18:40:00 -04:00
for ( int k = 0 ; k < MaterialSet . Materials . Num ( ) ; + + k )
{
DynamicMeshComponent - > SetMaterial ( k , MaterialSet . Materials [ k ] ) ;
}
2021-06-11 22:39:18 -04:00
FDynamicMesh3 InputMeshWithTangents = UE : : ToolTarget : : GetDynamicMeshCopy ( Targets [ 0 ] , true ) ;
DynamicMeshComponent - > SetTangentsType ( EDynamicMeshComponentTangentsMode : : ExternallyProvided ) ;
DynamicMeshComponent - > SetMesh ( MoveTemp ( InputMeshWithTangents ) ) ;
2020-06-23 18:40:00 -04:00
2021-06-11 22:39:18 -04:00
DynamicMeshComponent - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh )
{
BaseMesh . Copy ( ReadMesh ) ;
BaseMeshTangents = MakeShared < FMeshTangentsd , ESPMode : : ThreadSafe > ( & BaseMesh ) ;
BaseMeshTangents - > CopyTriVertexTangents ( ReadMesh ) ;
} ) ;
2020-06-23 18:40:00 -04:00
BaseSpatial . SetMesh ( & BaseMesh , true ) ;
2020-08-11 01:36:57 -04:00
2020-06-23 18:40:00 -04:00
UMaterial * Material = LoadObject < UMaterial > ( nullptr , TEXT ( " /MeshModelingToolset/Materials/BakePreviewMaterial " ) ) ;
check ( Material ) ;
if ( Material ! = nullptr )
{
PreviewMaterial = UMaterialInstanceDynamic : : Create ( Material , GetToolManager ( ) ) ;
DynamicMeshComponent - > SetOverrideRenderMaterial ( PreviewMaterial ) ;
}
2021-04-08 14:32:07 -04:00
UMaterial * BentNormalMaterial = LoadObject < UMaterial > ( nullptr , TEXT ( " /MeshModelingToolset/Materials/BakeBentNormalPreviewMaterial " ) ) ;
check ( BentNormalMaterial ) ;
2021-04-12 17:10:46 -04:00
if ( BentNormalMaterial ! = nullptr )
2021-04-08 14:32:07 -04:00
{
BentNormalPreviewMaterial = UMaterialInstanceDynamic : : Create ( BentNormalMaterial , GetToolManager ( ) ) ;
}
2021-04-12 17:10:46 -04:00
UMaterial * WorkingMaterial = LoadObject < UMaterial > ( nullptr , TEXT ( " /MeshModelingToolset/Materials/InProgressMaterial " ) ) ;
check ( WorkingMaterial ) ;
if ( WorkingMaterial ! = nullptr )
{
WorkingPreviewMaterial = UMaterialInstanceDynamic : : Create ( WorkingMaterial , GetToolManager ( ) ) ;
}
2020-06-23 18:40:00 -04:00
2021-02-23 18:03:26 -04:00
bIsBakeToSelf = ( Targets . Num ( ) = = 1 ) ;
2020-09-01 14:07:48 -04:00
2021-06-11 22:39:18 -04:00
UE : : ToolTarget : : HideSourceObject ( Targets [ 0 ] ) ;
2020-06-23 18:40:00 -04:00
Settings = NewObject < UBakeMeshAttributeMapsToolProperties > ( this ) ;
Settings - > RestoreProperties ( this ) ;
2020-09-01 14:07:48 -04:00
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 ] ;
}
2020-06-23 18:40:00 -04:00
AddToolPropertySource ( Settings ) ;
2021-06-03 15:29:38 -04:00
Settings - > WatchProperty ( Settings - > MapTypes , [ this ] ( int32 ) { bInputsDirty = true ; UpdateOnModeChange ( ) ; } ) ;
Settings - > WatchProperty ( Settings - > MapPreview , [ this ] ( int32 ) { UpdateVisualization ( ) ; GetToolManager ( ) - > PostInvalidation ( ) ; } ) ;
2021-04-12 17:10:46 -04:00
Settings - > WatchProperty ( Settings - > Resolution , [ this ] ( EBakeTextureResolution ) { bInputsDirty = true ; } ) ;
Settings - > WatchProperty ( Settings - > UVLayer , [ this ] ( FString ) { bInputsDirty = true ; } ) ;
Settings - > WatchProperty ( Settings - > bUseWorldSpace , [ this ] ( bool ) { bDetailMeshValid = false ; bInputsDirty = true ; } ) ;
Settings - > WatchProperty ( Settings - > Thickness , [ this ] ( float ) { bInputsDirty = true ; } ) ;
2021-05-17 16:01:01 -04:00
Settings - > WatchProperty ( Settings - > Multisampling , [ this ] ( EBakeMultisampling ) { bInputsDirty = true ; } ) ;
2020-06-23 18:40:00 -04:00
NormalMapProps = NewObject < UBakedNormalMapToolProperties > ( this ) ;
NormalMapProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( NormalMapProps ) ;
2020-09-01 14:07:48 -04:00
SetToolPropertySourceEnabled ( NormalMapProps , false ) ;
2020-06-23 18:40:00 -04:00
2020-09-01 14:07:48 -04:00
OcclusionMapProps = NewObject < UBakedOcclusionMapToolProperties > ( this ) ;
OcclusionMapProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( OcclusionMapProps ) ;
SetToolPropertySourceEnabled ( OcclusionMapProps , false ) ;
2021-04-12 17:10:46 -04:00
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > OcclusionRays , [ this ] ( int32 ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > MaxDistance , [ this ] ( float ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > SpreadAngle , [ this ] ( float ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > Distribution , [ this ] ( EOcclusionMapDistribution ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > BlurRadius , [ this ] ( float ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > bGaussianBlur , [ this ] ( float ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > BiasAngle , [ this ] ( float ) { bInputsDirty = true ; } ) ;
OcclusionMapProps - > WatchProperty ( OcclusionMapProps - > NormalSpace , [ this ] ( ENormalMapSpace ) { bInputsDirty = true ; } ) ;
2020-09-01 14:07:48 -04:00
CurvatureMapProps = NewObject < UBakedCurvatureMapToolProperties > ( this ) ;
CurvatureMapProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( CurvatureMapProps ) ;
SetToolPropertySourceEnabled ( CurvatureMapProps , false ) ;
2021-04-12 17:10:46 -04:00
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > RangeMultiplier , [ this ] ( float ) { bInputsDirty = true ; } ) ;
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > MinRangeMultiplier , [ this ] ( float ) { bInputsDirty = true ; } ) ;
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > CurvatureType , [ this ] ( EBakedCurvatureTypeMode ) { bInputsDirty = true ; } ) ;
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > ColorMode , [ this ] ( EBakedCurvatureColorMode ) { bInputsDirty = true ; } ) ;
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > Clamping , [ this ] ( EBakedCurvatureClampMode ) { bInputsDirty = true ; } ) ;
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > BlurRadius , [ this ] ( float ) { bInputsDirty = true ; } ) ;
CurvatureMapProps - > WatchProperty ( CurvatureMapProps - > bGaussianBlur , [ this ] ( float ) { bInputsDirty = true ; } ) ;
2020-09-01 14:07:48 -04:00
Texture2DProps = NewObject < UBakedTexture2DImageProperties > ( this ) ;
Texture2DProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( Texture2DProps ) ;
SetToolPropertySourceEnabled ( Texture2DProps , false ) ;
2021-04-12 17:10:46 -04:00
Texture2DProps - > WatchProperty ( Texture2DProps - > UVLayer , [ this ] ( float ) { bInputsDirty = true ; } ) ;
Texture2DProps - > WatchProperty ( Texture2DProps - > SourceTexture , [ this ] ( UTexture2D * ) { bInputsDirty = true ; } ) ;
2020-09-01 14:07:48 -04:00
2021-04-30 17:04:37 -04:00
MultiTextureProps = NewObject < UBakedMultiTexture2DImageProperties > ( this ) ;
MultiTextureProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( MultiTextureProps ) ;
SetToolPropertySourceEnabled ( MultiTextureProps , false ) ;
2021-06-11 10:09:47 -04:00
auto SetDirtyCallback = [ this ] ( decltype ( MultiTextureProps - > MaterialIDSourceTextureMap ) ) { bInputsDirty = true ; } ;
auto NotEqualsCallback = [ ] ( const decltype ( MultiTextureProps - > MaterialIDSourceTextureMap ) & A , const decltype ( MultiTextureProps - > MaterialIDSourceTextureMap ) & B ) - > bool { return ! ( A . OrderIndependentCompareEqual ( B ) ) ; } ;
2021-05-04 14:01:08 -04:00
MultiTextureProps - > WatchProperty ( MultiTextureProps - > MaterialIDSourceTextureMap , SetDirtyCallback , NotEqualsCallback ) ;
2021-04-30 17:04:37 -04:00
MultiTextureProps - > WatchProperty ( MultiTextureProps - > UVLayer , [ this ] ( float ) { bInputsDirty = true ; } ) ;
2020-06-23 18:40:00 -04:00
VisualizationProps = NewObject < UBakedOcclusionMapVisualizationProperties > ( this ) ;
VisualizationProps - > RestoreProperties ( this ) ;
AddToolPropertySource ( VisualizationProps ) ;
InitializeEmptyMaps ( ) ;
2021-06-03 15:29:38 -04:00
UpdateOnModeChange ( ) ;
2020-06-23 18:40:00 -04:00
2021-04-12 17:10:46 -04:00
bInputsDirty = true ;
2020-09-01 14:07:48 -04:00
bDetailMeshValid = false ;
2020-06-23 18:40:00 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " ToolName " , " Bake Textures " ) ) ;
2020-06-23 18:40:00 -04:00
GetToolManager ( ) - > DisplayMessage (
2021-02-08 17:02:09 -04:00
LOCTEXT ( " OnStartTool " , " Bake Maps. Select Bake Mesh (LowPoly) first, then (optionally) Detail Mesh second. Texture Assets will be created on Accept. " ) ,
2020-06-23 18:40:00 -04:00
EToolMessageLevel : : UserNotification ) ;
}
2020-09-01 14:07:48 -04:00
bool UBakeMeshAttributeMapsTool : : CanAccept ( ) const
{
2021-04-12 17:10:46 -04:00
bool bCanAccept = Compute ? Compute - > HaveValidResult ( ) : false ;
if ( bCanAccept )
2021-04-08 14:32:07 -04:00
{
2021-06-03 15:29:38 -04:00
// Allow Accept if all non-None types have valid results.
int NumResults = Settings - > Result . Num ( ) ;
for ( int ResultIdx = 0 ; ResultIdx < NumResults ; + + ResultIdx )
2021-04-12 17:10:46 -04:00
{
2021-06-03 15:29:38 -04:00
bCanAccept = bCanAccept & & Settings - > Result [ ResultIdx ] ;
2021-04-12 17:10:46 -04:00
}
2021-04-08 14:32:07 -04:00
}
return bCanAccept ;
2020-09-01 14:07:48 -04:00
}
2021-05-17 16:01:01 -04:00
TUniquePtr < UE : : Geometry : : TGenericDataOperator < FMeshMapBaker > > UBakeMeshAttributeMapsTool : : MakeNewOperator ( )
2021-04-12 17:10:46 -04:00
{
2021-06-03 15:29:38 -04:00
TUniquePtr < FMeshMapBakerOp > Op = MakeUnique < FMeshMapBakerOp > ( ) ;
Op - > DetailMesh = DetailMesh ;
Op - > DetailSpatial = DetailSpatial ;
Op - > BaseMesh = & BaseMesh ;
Op - > BakeCacheSettings = CachedBakeCacheSettings ;
2021-05-17 16:01:01 -04:00
2021-06-03 15:29:38 -04:00
const EBakeMapType RequiresTangents = EBakeMapType : : TangentSpaceNormalMap | EBakeMapType : : BentNormal ;
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & RequiresTangents ) )
2021-04-12 17:10:46 -04:00
{
2021-05-17 16:01:01 -04:00
Op - > BaseMeshTangents = BaseMeshTangents ;
2021-04-12 17:10:46 -04:00
}
2021-06-03 15:29:38 -04:00
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : TangentSpaceNormalMap ) )
2021-04-12 17:10:46 -04:00
{
2021-06-03 15:29:38 -04:00
Op - > NormalSettings = CachedNormalMapSettings ;
2021-04-12 17:10:46 -04:00
}
2021-06-03 15:29:38 -04:00
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : AmbientOcclusion ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : BentNormal ) )
2021-04-12 17:10:46 -04:00
{
2021-06-03 15:29:38 -04:00
Op - > OcclusionSettings = CachedOcclusionMapSettings ;
2021-04-12 17:10:46 -04:00
}
2021-06-03 15:29:38 -04:00
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : Curvature ) )
2021-04-12 17:10:46 -04:00
{
2021-06-03 15:29:38 -04:00
Op - > CurvatureSettings = CachedCurvatureMapSettings ;
2021-04-12 17:10:46 -04:00
}
2021-06-03 15:29:38 -04:00
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : NormalImage ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : FaceNormalImage ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : PositionImage ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : MaterialID ) )
2021-04-12 17:10:46 -04:00
{
2021-06-03 15:29:38 -04:00
Op - > PropertySettings = CachedMeshPropertyMapSettings ;
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : Texture2DImage ) )
{
Op - > TextureSettings = CachedTexture2DImageSettings ;
2021-04-12 17:10:46 -04:00
Op - > TextureImage = CachedTextureImage ;
2021-04-30 17:04:37 -04:00
Op - > UVOverlay = DetailMesh - > Attributes ( ) - > GetUVLayer ( CachedTexture2DImageSettings . UVLayer ) ;
2021-06-03 15:29:38 -04:00
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : MultiTexture ) )
{
Op - > TextureSettings = CachedTexture2DImageSettings ;
2021-04-30 17:04:37 -04:00
Op - > MaterialToTextureImageMap = CachedMultiTextures ;
2021-06-03 15:29:38 -04:00
Op - > UVOverlay = DetailMesh - > Attributes ( ) - > GetUVLayer ( CachedTexture2DImageSettings . UVLayer ) ;
2021-04-30 17:04:37 -04:00
}
2021-06-03 15:29:38 -04:00
return Op ;
2021-04-12 17:10:46 -04:00
}
2020-06-23 18:40:00 -04:00
void UBakeMeshAttributeMapsTool : : Shutdown ( EToolShutdownType ShutdownType )
{
Settings - > SaveProperties ( this ) ;
OcclusionMapProps - > SaveProperties ( this ) ;
NormalMapProps - > SaveProperties ( this ) ;
2020-09-01 14:07:48 -04:00
CurvatureMapProps - > SaveProperties ( this ) ;
Texture2DProps - > SaveProperties ( this ) ;
2021-04-30 17:04:37 -04:00
MultiTextureProps - > SaveProperties ( this ) ;
2020-06-23 18:40:00 -04:00
VisualizationProps - > SaveProperties ( this ) ;
2021-04-12 17:10:46 -04:00
if ( Compute )
{
Compute - > Shutdown ( ) ;
}
2020-06-23 18:40:00 -04:00
if ( DynamicMeshComponent ! = nullptr )
{
2021-06-11 22:39:18 -04:00
UE : : ToolTarget : : ShowSourceObject ( Targets [ 0 ] ) ;
2020-06-23 18:40:00 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
2021-06-11 22:39:18 -04:00
UStaticMeshComponent * StaticMeshComponent = CastChecked < UStaticMeshComponent > ( UE : : ToolTarget : : GetTargetComponent ( Targets [ 0 ] ) ) ;
2020-08-11 01:36:57 -04:00
UStaticMesh * StaticMeshAsset = StaticMeshComponent - > GetStaticMesh ( ) ;
check ( StaticMeshAsset ) ;
2021-06-11 22:39:18 -04:00
FString BaseName = UE : : ToolTarget : : GetTargetActor ( Targets [ 0 ] ) - > GetName ( ) ;
2020-06-23 18:40:00 -04:00
2021-06-03 15:29:38 -04:00
bool bCreatedAssetOK = true ;
int NumResults = Settings - > Result . Num ( ) ;
for ( int ResultIdx = 0 ; ResultIdx < NumResults ; + + ResultIdx )
2020-06-23 18:40:00 -04:00
{
2021-06-03 15:29:38 -04:00
FTexture2DBuilder : : ETextureType TexType = FTexture2DBuilder : : ETextureType : : Color ;
FString TexName ;
switch ( ResultTypes [ ResultIdx ] )
{
default :
// Should never reach this case.
check ( false ) ;
continue ;
case EBakeMapType : : TangentSpaceNormalMap :
TexName = FString : : Printf ( TEXT ( " %s_Normals " ) , * BaseName ) ;
TexType = FTexture2DBuilder : : ETextureType : : NormalMap ;
break ;
case EBakeMapType : : AmbientOcclusion :
TexName = FString : : Printf ( TEXT ( " %s_Occlusion " ) , * BaseName ) ;
TexType = FTexture2DBuilder : : ETextureType : : AmbientOcclusion ;
break ;
case EBakeMapType : : BentNormal :
TexName = FString : : Printf ( TEXT ( " %s_BentNormal " ) , * BaseName ) ;
TexType = FTexture2DBuilder : : ETextureType : : NormalMap ;
break ;
case EBakeMapType : : Curvature :
TexName = FString : : Printf ( TEXT ( " %s_Curvature " ) , * BaseName ) ;
break ;
case EBakeMapType : : NormalImage :
TexName = FString : : Printf ( TEXT ( " %s_NormalImg " ) , * BaseName ) ;
break ;
case EBakeMapType : : FaceNormalImage :
TexName = FString : : Printf ( TEXT ( " %s_FaceNormalImg " ) , * BaseName ) ;
break ;
case EBakeMapType : : MaterialID :
TexName = FString : : Printf ( TEXT ( " %s_MaterialIDImg " ) , * BaseName ) ;
break ;
case EBakeMapType : : PositionImage :
TexName = FString : : Printf ( TEXT ( " %s_PositionImg " ) , * BaseName ) ;
TexType = FTexture2DBuilder : : ETextureType : : Color ;
break ;
case EBakeMapType : : Texture2DImage :
TexName = FString : : Printf ( TEXT ( " %s_TextureImg " ) , * BaseName ) ;
TexType = FTexture2DBuilder : : ETextureType : : Color ;
break ;
case EBakeMapType : : MultiTexture :
TexName = FString : : Printf ( TEXT ( " %s_MultiTextureImg " ) , * BaseName ) ;
TexType = FTexture2DBuilder : : ETextureType : : Color ;
break ;
}
FTexture2DBuilder : : CopyPlatformDataToSourceData ( Settings - > Result [ ResultIdx ] , TexType ) ;
bCreatedAssetOK = bCreatedAssetOK & & UE : : Modeling : : CreateTextureObject ( GetToolManager ( ) , FCreateTextureObjectParams { 0 , StaticMeshAsset - > GetWorld ( ) , StaticMeshAsset , TexName , Settings - > Result [ ResultIdx ] } ) . IsOK ( ) ;
2020-06-23 18:40:00 -04:00
}
2021-06-02 15:58:00 -04:00
ensure ( bCreatedAssetOK ) ;
2020-06-23 18:40:00 -04:00
}
DynamicMeshComponent - > UnregisterComponent ( ) ;
DynamicMeshComponent - > DestroyComponent ( ) ;
DynamicMeshComponent = nullptr ;
}
}
2021-04-12 17:10:46 -04:00
void UBakeMeshAttributeMapsTool : : OnTick ( float DeltaTime )
{
if ( Compute )
{
Compute - > Tick ( DeltaTime ) ;
float ElapsedComputeTime = Compute - > GetElapsedComputeTime ( ) ;
if ( ! CanAccept ( ) & & ElapsedComputeTime > SecondsBeforeWorkingMaterial )
{
DynamicMeshComponent - > SetOverrideRenderMaterial ( WorkingPreviewMaterial ) ;
}
}
}
2020-06-23 18:40:00 -04:00
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 ) ;
}
2021-04-30 17:04:37 -04:00
int SelectTextureToBake ( 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 )
{
+ + 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 ;
}
2021-06-11 22:39:18 -04:00
void UBakeMeshAttributeMapsTool : : GetTexturesFromDetailMesh ( const UPrimitiveComponent * DetailComponent )
2021-04-30 17:04:37 -04:00
{
constexpr bool bGuessAtTextures = true ;
MultiTextureProps - > AllSourceTextures . Reset ( ) ;
MultiTextureProps - > MaterialIDSourceTextureMap . Reset ( ) ;
TArray < UMaterialInterface * > Materials ;
2021-06-11 22:39:18 -04:00
DetailComponent - > GetUsedMaterials ( Materials ) ;
2021-04-30 17:04:37 -04:00
for ( int32 MaterialID = 0 ; MaterialID < Materials . Num ( ) ; + + MaterialID ) // TODO: This won't match MaterialIDs on the FDynamicMesh3 in general, will it?
{
UMaterialInterface * MaterialInterface = Materials [ MaterialID ] ;
if ( MaterialInterface = = nullptr )
{
continue ;
}
TArray < UTexture * > Textures ;
MaterialInterface - > GetUsedTextures ( Textures , EMaterialQualityLevel : : High , true , ERHIFeatureLevel : : SM5 , true ) ;
for ( UTexture * Tex : Textures )
{
UTexture2D * Tex2D = Cast < UTexture2D > ( Tex ) ;
if ( Tex2D )
{
MultiTextureProps - > AllSourceTextures . Add ( Tex2D ) ;
}
}
if ( bGuessAtTextures )
{
int SelectedTextureIndex = SelectTextureToBake ( Textures ) ;
if ( SelectedTextureIndex > = 0 )
{
UTexture2D * Tex2D = Cast < UTexture2D > ( Textures [ SelectedTextureIndex ] ) ;
// if cast fails, this will set the value to nullptr, which is fine
MultiTextureProps - > MaterialIDSourceTextureMap . Add ( MaterialID , Tex2D ) ;
}
}
else
{
MultiTextureProps - > MaterialIDSourceTextureMap . Add ( MaterialID , nullptr ) ;
}
}
}
2020-09-01 14:07:48 -04:00
void UBakeMeshAttributeMapsTool : : UpdateDetailMesh ( )
2020-06-23 18:40:00 -04:00
{
2021-06-11 22:39:18 -04:00
UToolTarget * DetailTarget = Targets [ bIsBakeToSelf ? 0 : 1 ] ;
DetailMesh = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( UE : : ToolTarget : : GetDynamicMeshCopy ( DetailTarget ) ) ;
2021-02-23 18:03:26 -04:00
2020-09-01 14:07:48 -04:00
if ( Settings - > bUseWorldSpace & & bIsBakeToSelf = = false )
{
2021-06-11 22:39:18 -04:00
FTransform3d DetailToWorld = UE : : ToolTarget : : GetLocalToWorldTransform ( DetailTarget ) ;
2020-09-01 14:07:48 -04:00
MeshTransforms : : ApplyTransform ( * DetailMesh , DetailToWorld ) ;
2021-06-11 22:39:18 -04:00
FTransform3d WorldToBase = UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ 0 ] ) ;
2020-09-01 14:07:48 -04:00
MeshTransforms : : ApplyTransform ( * DetailMesh , WorldToBase . Inverse ( ) ) ;
}
2021-02-17 11:50:23 -04:00
DetailSpatial = MakeShared < FDynamicMeshAABBTree3 , ESPMode : : ThreadSafe > ( ) ;
2020-09-01 14:07:48 -04:00
DetailSpatial - > SetMesh ( DetailMesh . Get ( ) , true ) ;
2021-06-11 22:39:18 -04:00
GetTexturesFromDetailMesh ( UE : : ToolTarget : : GetTargetComponent ( DetailTarget ) ) ;
2021-04-30 17:04:37 -04:00
2021-04-12 17:10:46 -04:00
bInputsDirty = true ;
2020-09-01 14:07:48 -04:00
DetailMeshTimestamp + + ;
2021-04-30 17:04:37 -04:00
2020-06-23 18:40:00 -04:00
}
void UBakeMeshAttributeMapsTool : : UpdateResult ( )
{
2020-09-01 14:07:48 -04:00
if ( bDetailMeshValid = = false )
{
UpdateDetailMesh ( ) ;
bDetailMeshValid = true ;
2020-11-17 22:32:38 -04:00
CachedBakeCacheSettings = FBakeCacheSettings ( ) ;
2020-09-01 14:07:48 -04:00
}
2021-04-12 17:10:46 -04:00
// bInputsDirty ensures that we only validate parameters once per param
// change. Parameter validation can be expensive (ex. UpdateResult_Texture2DImage).
if ( ! bInputsDirty )
2020-06-23 18:40:00 -04:00
{
return ;
}
2020-09-01 14:07:48 -04:00
// clear warning (ugh)
GetToolManager ( ) - > DisplayMessage ( FText ( ) , EToolMessageLevel : : UserWarning ) ;
2020-06-23 18:40:00 -04:00
int32 ImageSize = ( int32 ) Settings - > Resolution ;
FImageDimensions Dimensions ( ImageSize , ImageSize ) ;
2020-09-01 14:07:48 -04:00
FBakeCacheSettings BakeCacheSettings ;
BakeCacheSettings . Dimensions = Dimensions ;
BakeCacheSettings . UVLayer = FCString : : Atoi ( * Settings - > UVLayer ) ;
BakeCacheSettings . DetailTimestamp = this - > DetailMeshTimestamp ;
2020-11-17 22:32:38 -04:00
BakeCacheSettings . Thickness = Settings - > Thickness ;
2021-05-17 16:01:01 -04:00
BakeCacheSettings . Multisampling = ( int32 ) Settings - > Multisampling ;
2020-06-23 18:40:00 -04:00
2021-06-03 15:29:38 -04:00
// process the raw bitfield before caching which may add additional targets.
BakeCacheSettings . BakeMapTypes = GetMapTypes ( Settings - > MapTypes ) ;
2021-04-12 17:10:46 -04:00
// update bake cache settings
2020-09-01 14:07:48 -04:00
if ( ! ( CachedBakeCacheSettings = = BakeCacheSettings ) )
2020-06-23 18:40:00 -04:00
{
2020-11-17 22:32:38 -04:00
CachedBakeCacheSettings = BakeCacheSettings ;
CachedNormalMapSettings = FNormalMapSettings ( ) ;
CachedOcclusionMapSettings = FOcclusionMapSettings ( ) ;
CachedCurvatureMapSettings = FCurvatureMapSettings ( ) ;
CachedMeshPropertyMapSettings = FMeshPropertyMapSettings ( ) ;
CachedTexture2DImageSettings = FTexture2DImageSettings ( ) ;
2020-06-23 18:40:00 -04:00
}
2021-06-03 15:29:38 -04:00
// Clear our invalid bitflag to check again for valid inputs.
OpState = EBakeOpState : : Evaluate ;
// Update map type settings
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : TangentSpaceNormalMap ) )
2020-06-23 18:40:00 -04:00
{
2021-06-03 15:29:38 -04:00
OpState | = UpdateResult_Normal ( ) ;
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : AmbientOcclusion ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : BentNormal ) )
{
OpState | = UpdateResult_Occlusion ( ) ;
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : Curvature ) )
{
OpState | = UpdateResult_Curvature ( ) ;
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : NormalImage ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : FaceNormalImage ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : PositionImage ) | |
( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : MaterialID ) )
{
OpState | = UpdateResult_MeshProperty ( ) ;
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : Texture2DImage ) )
{
OpState | = UpdateResult_Texture2DImage ( ) ;
}
if ( ( bool ) ( CachedBakeCacheSettings . BakeMapTypes & EBakeMapType : : MultiTexture ) )
{
OpState | = UpdateResult_MultiTexture ( ) ;
2020-06-23 18:40:00 -04:00
}
2021-04-12 17:10:46 -04:00
// Early exit if op input parameters are invalid.
2021-06-03 15:29:38 -04:00
if ( ( bool ) ( OpState & EBakeOpState : : Invalid ) )
2021-04-12 17:10:46 -04:00
{
return ;
}
2020-06-23 18:40:00 -04:00
2021-04-12 17:10:46 -04:00
// This should be the only point of compute invalidation to
// minimize synchronization issues.
2021-06-03 15:29:38 -04:00
bool bInvalidate = bInputsDirty | | ( bool ) ( OpState & EBakeOpState : : Evaluate ) ;
2021-04-12 17:10:46 -04:00
if ( ! Compute )
{
2021-05-17 16:01:01 -04:00
Compute = MakeUnique < TGenericDataBackgroundCompute < FMeshMapBaker > > ( ) ;
2021-04-12 17:10:46 -04:00
Compute - > Setup ( this ) ;
2021-05-17 16:01:01 -04:00
Compute - > OnResultUpdated . AddLambda ( [ this ] ( const TUniquePtr < FMeshMapBaker > & NewResult ) { OnMapsUpdated ( NewResult ) ; } ) ;
2021-04-12 17:10:46 -04:00
Compute - > InvalidateResult ( ) ;
}
else if ( bInvalidate )
{
Compute - > InvalidateResult ( ) ;
}
bInputsDirty = false ;
2020-06-23 18:40:00 -04:00
}
2021-06-03 15:29:38 -04:00
EBakeOpState UBakeMeshAttributeMapsTool : : UpdateResult_Normal ( )
2020-09-01 14:07:48 -04:00
{
2021-06-03 15:29:38 -04:00
EBakeOpState ResultState = EBakeOpState : : Complete ;
2020-09-01 14:07:48 -04:00
int32 ImageSize = ( int32 ) Settings - > Resolution ;
FImageDimensions Dimensions ( ImageSize , ImageSize ) ;
FNormalMapSettings NormalMapSettings ;
NormalMapSettings . Dimensions = Dimensions ;
if ( ! ( CachedNormalMapSettings = = NormalMapSettings ) )
{
CachedNormalMapSettings = NormalMapSettings ;
2021-06-03 15:29:38 -04:00
ResultState = EBakeOpState : : Evaluate ;
2020-09-01 14:07:48 -04:00
}
2021-04-12 17:10:46 -04:00
return ResultState ;
2020-09-01 14:07:48 -04:00
}
2021-06-03 15:29:38 -04:00
EBakeOpState UBakeMeshAttributeMapsTool : : UpdateResult_Occlusion ( )
2020-09-01 14:07:48 -04:00
{
2021-06-03 15:29:38 -04:00
EBakeOpState ResultState = EBakeOpState : : Complete ;
2020-09-01 14:07:48 -04:00
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 ;
2021-04-08 14:32:07 -04:00
OcclusionMapSettings . SpreadAngle = OcclusionMapProps - > SpreadAngle ;
OcclusionMapSettings . Distribution = OcclusionMapProps - > Distribution ;
2020-09-01 14:07:48 -04:00
OcclusionMapSettings . BlurRadius = ( OcclusionMapProps - > bGaussianBlur ) ? OcclusionMapProps - > BlurRadius : 0.0 ;
OcclusionMapSettings . BiasAngle = OcclusionMapProps - > BiasAngle ;
2021-04-08 14:32:07 -04:00
OcclusionMapSettings . NormalSpace = OcclusionMapProps - > NormalSpace ;
2020-09-01 14:07:48 -04:00
if ( ! ( CachedOcclusionMapSettings = = OcclusionMapSettings ) )
{
CachedOcclusionMapSettings = OcclusionMapSettings ;
2021-06-03 15:29:38 -04:00
ResultState = EBakeOpState : : Evaluate ;
2020-09-01 14:07:48 -04:00
}
2021-04-12 17:10:46 -04:00
return ResultState ;
2020-09-01 14:07:48 -04:00
}
2021-06-03 15:29:38 -04:00
EBakeOpState UBakeMeshAttributeMapsTool : : UpdateResult_Curvature ( )
2020-09-01 14:07:48 -04:00
{
2021-06-03 15:29:38 -04:00
EBakeOpState ResultState = EBakeOpState : : Complete ;
2020-09-01 14:07:48 -04:00
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 :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . CurvatureType = ( int32 ) FMeshCurvatureMapEvaluator : : ECurvatureType : : Mean ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureTypeMode : : Gaussian :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . CurvatureType = ( int32 ) FMeshCurvatureMapEvaluator : : ECurvatureType : : Gaussian ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureTypeMode : : Max :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . CurvatureType = ( int32 ) FMeshCurvatureMapEvaluator : : ECurvatureType : : MaxPrincipal ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureTypeMode : : Min :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . CurvatureType = ( int32 ) FMeshCurvatureMapEvaluator : : ECurvatureType : : MinPrincipal ;
2020-09-01 14:07:48 -04:00
break ;
}
switch ( CurvatureMapProps - > ColorMode )
{
default :
case EBakedCurvatureColorMode : : Grayscale :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . ColorMode = ( int32 ) FMeshCurvatureMapEvaluator : : EColorMode : : BlackGrayWhite ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureColorMode : : RedBlue :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . ColorMode = ( int32 ) FMeshCurvatureMapEvaluator : : EColorMode : : RedBlue ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureColorMode : : RedGreenBlue :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . ColorMode = ( int32 ) FMeshCurvatureMapEvaluator : : EColorMode : : RedGreenBlue ;
2020-09-01 14:07:48 -04:00
break ;
}
switch ( CurvatureMapProps - > Clamping )
{
default :
case EBakedCurvatureClampMode : : None :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . ClampMode = ( int32 ) FMeshCurvatureMapEvaluator : : EClampMode : : FullRange ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureClampMode : : Positive :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . ClampMode = ( int32 ) FMeshCurvatureMapEvaluator : : EClampMode : : Positive ;
2020-09-01 14:07:48 -04:00
break ;
case EBakedCurvatureClampMode : : Negative :
2021-05-26 17:14:57 -04:00
CurvatureMapSettings . ClampMode = ( int32 ) FMeshCurvatureMapEvaluator : : EClampMode : : Negative ;
2020-09-01 14:07:48 -04:00
break ;
}
CurvatureMapSettings . BlurRadius = ( CurvatureMapProps - > bGaussianBlur ) ? CurvatureMapProps - > BlurRadius : 0.0 ;
if ( ! ( CachedCurvatureMapSettings = = CurvatureMapSettings ) )
{
CachedCurvatureMapSettings = CurvatureMapSettings ;
2021-06-03 15:29:38 -04:00
ResultState = EBakeOpState : : Evaluate ;
2020-09-01 14:07:48 -04:00
}
2021-04-12 17:10:46 -04:00
return ResultState ;
2020-09-01 14:07:48 -04:00
}
2021-06-03 15:29:38 -04:00
EBakeOpState UBakeMeshAttributeMapsTool : : UpdateResult_MeshProperty ( )
2020-09-01 14:07:48 -04:00
{
2021-06-03 15:29:38 -04:00
EBakeOpState ResultState = EBakeOpState : : Complete ;
2020-09-01 14:07:48 -04:00
int32 ImageSize = ( int32 ) Settings - > Resolution ;
FImageDimensions Dimensions ( ImageSize , ImageSize ) ;
FMeshPropertyMapSettings MeshPropertyMapSettings ;
MeshPropertyMapSettings . Dimensions = Dimensions ;
if ( ! ( CachedMeshPropertyMapSettings = = MeshPropertyMapSettings ) )
{
CachedMeshPropertyMapSettings = MeshPropertyMapSettings ;
2021-06-03 15:29:38 -04:00
ResultState = EBakeOpState : : Evaluate ;
2020-09-01 14:07:48 -04:00
}
2021-04-12 17:10:46 -04:00
return ResultState ;
2020-09-01 14:07:48 -04:00
}
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 } ;
} ;
2021-06-03 15:29:38 -04:00
EBakeOpState UBakeMeshAttributeMapsTool : : UpdateResult_Texture2DImage ( )
2020-09-01 14:07:48 -04:00
{
2021-06-03 15:29:38 -04:00
EBakeOpState ResultState = EBakeOpState : : Complete ;
2020-09-01 14:07:48 -04:00
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 ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2020-09-01 14:07:48 -04:00
}
if ( Texture2DProps - > SourceTexture = = nullptr )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " InvalidTextureWarning " , " The Source Texture is not valid " ) , EToolMessageLevel : : UserWarning ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2020-09-01 14:07:48 -04:00
}
{
FTempTextureAccess TextureAccess ( Texture2DProps - > SourceTexture ) ;
2021-04-12 17:10:46 -04:00
CachedTextureImage = MakeShared < UE : : Geometry : : TImageBuilder < FVector4f > , ESPMode : : ThreadSafe > ( ) ;
CachedTextureImage - > SetDimensions ( TextureAccess . GetDimensions ( ) ) ;
if ( ! TextureAccess . CopyTo ( * CachedTextureImage ) )
2020-09-01 14:07:48 -04:00
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " CannotReadTextureWarning " , " Cannot read from the source texture " ) , EToolMessageLevel : : UserWarning ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2020-09-01 14:07:48 -04:00
}
}
if ( ! ( CachedTexture2DImageSettings = = NewSettings ) )
{
CachedTexture2DImageSettings = NewSettings ;
2021-06-03 15:29:38 -04:00
ResultState = EBakeOpState : : Evaluate ;
2020-09-01 14:07:48 -04:00
}
2021-04-12 17:10:46 -04:00
return ResultState ;
2020-09-01 14:07:48 -04:00
}
2021-06-03 15:29:38 -04:00
EBakeOpState UBakeMeshAttributeMapsTool : : UpdateResult_MultiTexture ( )
2021-04-30 17:04:37 -04:00
{
2021-06-03 15:29:38 -04:00
EBakeOpState ResultState = EBakeOpState : : Complete ;
2021-04-30 17:04:37 -04:00
int32 ImageSize = ( int32 ) Settings - > Resolution ;
FImageDimensions Dimensions ( ImageSize , ImageSize ) ;
FTexture2DImageSettings NewSettings ;
NewSettings . Dimensions = Dimensions ;
NewSettings . UVLayer = MultiTextureProps - > 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 ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2021-04-30 17:04:37 -04:00
}
2021-06-11 10:09:47 -04:00
for ( auto & InputTexture : MultiTextureProps - > MaterialIDSourceTextureMap )
2021-04-30 17:04:37 -04:00
{
if ( InputTexture . Value = = nullptr )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " InvalidTextureWarning " , " The Source Texture is not valid " ) , EToolMessageLevel : : UserWarning ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2021-04-30 17:04:37 -04:00
}
}
CachedMultiTextures . Reset ( ) ;
2021-06-11 10:09:47 -04:00
for ( auto & InputTexture : MultiTextureProps - > MaterialIDSourceTextureMap )
2021-04-30 17:04:37 -04:00
{
UTexture2D * Texture = InputTexture . Value ;
if ( ! ensure ( Texture ! = nullptr ) )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " InvalidTextureWarning " , " The Source Texture is not valid " ) , EToolMessageLevel : : UserWarning ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2021-04-30 17:04:37 -04:00
}
int32 MaterialID = InputTexture . Key ;
FTempTextureAccess TextureAccess ( Texture ) ;
CachedMultiTextures . Add ( MaterialID , MakeShared < UE : : Geometry : : TImageBuilder < FVector4f > , ESPMode : : ThreadSafe > ( ) ) ;
CachedMultiTextures [ MaterialID ] - > SetDimensions ( TextureAccess . GetDimensions ( ) ) ;
if ( ! TextureAccess . CopyTo ( * CachedMultiTextures [ MaterialID ] ) )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " CannotReadTextureWarning " , " Cannot read from the source texture " ) , EToolMessageLevel : : UserWarning ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2021-04-30 17:04:37 -04:00
}
}
2021-05-17 16:01:01 -04:00
if ( CachedMultiTextures . Num ( ) = = 0 )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " InvalidTextureWarning " , " The Source Texture is not valid " ) , EToolMessageLevel : : UserWarning ) ;
2021-06-03 15:29:38 -04:00
return EBakeOpState : : Invalid ;
2021-05-17 16:01:01 -04:00
}
2021-04-30 17:04:37 -04:00
if ( ! ( CachedTexture2DImageSettings = = NewSettings ) )
{
CachedTexture2DImageSettings = NewSettings ;
2021-06-03 15:29:38 -04:00
ResultState = EBakeOpState : : Evaluate ;
2021-04-30 17:04:37 -04:00
}
return ResultState ;
}
2020-09-01 14:07:48 -04:00
2020-06-23 18:40:00 -04:00
void UBakeMeshAttributeMapsTool : : UpdateVisualization ( )
{
2021-04-08 14:32:07 -04:00
DynamicMeshComponent - > SetOverrideRenderMaterial ( PreviewMaterial ) ;
2021-06-03 15:29:38 -04:00
// Map CachedMaps to Settings->Result
int NumResults = Settings - > Result . Num ( ) ;
for ( int ResultIdx = 0 ; ResultIdx < NumResults ; ResultIdx + + )
2020-06-23 18:40:00 -04:00
{
2021-06-03 15:29:38 -04:00
Settings - > Result [ ResultIdx ] = CachedMaps [ CachedMapIndices [ ResultTypes [ ResultIdx ] ] ] ;
}
// Set the preview material according to the preview index.
if ( Settings - > MapPreview > = 0 & & Settings - > MapPreview < Settings - > Result . Num ( ) )
{
const EBakeMapType & PreviewMapType = ResultTypes [ Settings - > MapPreview ] ;
if ( PreviewMapType ! = EBakeMapType : : None )
2021-04-08 14:32:07 -04:00
{
2021-06-03 15:29:38 -04:00
UTexture2D * PreviewMap = CachedMaps [ CachedMapIndices [ PreviewMapType ] ] ;
switch ( PreviewMapType )
{
default :
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " NormalMap " ) , EmptyNormalMap ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " OcclusionMap " ) , EmptyColorMapWhite ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " ColorMap " ) , EmptyColorMapWhite ) ;
break ;
case EBakeMapType : : TangentSpaceNormalMap :
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " NormalMap " ) , PreviewMap ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " OcclusionMap " ) , EmptyColorMapWhite ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " ColorMap " ) , EmptyColorMapWhite ) ;
break ;
case EBakeMapType : : AmbientOcclusion :
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " NormalMap " ) , EmptyNormalMap ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " OcclusionMap " ) , PreviewMap ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " ColorMap " ) , EmptyColorMapWhite ) ;
break ;
case EBakeMapType : : BentNormal :
BentNormalPreviewMaterial - > SetTextureParameterValue ( TEXT ( " NormalMap " ) , EmptyNormalMap ) ;
if ( CachedMapIndices . Contains ( EBakeMapType : : AmbientOcclusion ) )
{
BentNormalPreviewMaterial - > SetTextureParameterValue ( TEXT ( " OcclusionMap " ) , CachedMaps [ CachedMapIndices [ EBakeMapType : : AmbientOcclusion ] ] ) ;
}
else
{
BentNormalPreviewMaterial - > SetTextureParameterValue ( TEXT ( " OcclusionMap " ) , EmptyColorMapWhite ) ;
}
BentNormalPreviewMaterial - > SetTextureParameterValue ( TEXT ( " ColorMap " ) , EmptyColorMapWhite ) ;
BentNormalPreviewMaterial - > SetTextureParameterValue ( TEXT ( " BentNormalMap " ) , PreviewMap ) ;
DynamicMeshComponent - > SetOverrideRenderMaterial ( BentNormalPreviewMaterial ) ;
break ;
case EBakeMapType : : Curvature :
case EBakeMapType : : NormalImage :
case EBakeMapType : : FaceNormalImage :
case EBakeMapType : : PositionImage :
case EBakeMapType : : MaterialID :
case EBakeMapType : : Texture2DImage :
case EBakeMapType : : MultiTexture :
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " NormalMap " ) , EmptyNormalMap ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " OcclusionMap " ) , EmptyColorMapWhite ) ;
PreviewMaterial - > SetTextureParameterValue ( TEXT ( " ColorMap " ) , PreviewMap ) ;
break ;
}
2021-04-08 14:32:07 -04:00
}
2020-06-23 18:40:00 -04:00
}
2020-09-01 14:07:48 -04:00
}
void UBakeMeshAttributeMapsTool : : UpdateOnModeChange ( )
{
SetToolPropertySourceEnabled ( NormalMapProps , false ) ;
SetToolPropertySourceEnabled ( OcclusionMapProps , false ) ;
SetToolPropertySourceEnabled ( CurvatureMapProps , false ) ;
SetToolPropertySourceEnabled ( Texture2DProps , false ) ;
2021-04-30 17:04:37 -04:00
SetToolPropertySourceEnabled ( MultiTextureProps , false ) ;
2020-09-01 14:07:48 -04:00
2021-06-03 15:29:38 -04:00
for ( const EBakeMapType MapType : ALL_BAKE_MAP_TYPES )
2020-06-23 18:40:00 -04:00
{
2021-06-03 15:29:38 -04:00
switch ( ( EBakeMapType ) Settings - > MapTypes & MapType )
{
case EBakeMapType : : TangentSpaceNormalMap :
SetToolPropertySourceEnabled ( NormalMapProps , true ) ;
break ;
case EBakeMapType : : AmbientOcclusion :
case EBakeMapType : : BentNormal :
case EBakeMapType : : Occlusion :
SetToolPropertySourceEnabled ( OcclusionMapProps , true ) ;
break ;
case EBakeMapType : : Curvature :
SetToolPropertySourceEnabled ( CurvatureMapProps , true ) ;
break ;
case EBakeMapType : : NormalImage :
case EBakeMapType : : FaceNormalImage :
case EBakeMapType : : PositionImage :
case EBakeMapType : : MaterialID :
break ;
case EBakeMapType : : Texture2DImage :
SetToolPropertySourceEnabled ( Texture2DProps , true ) ;
break ;
case EBakeMapType : : MultiTexture :
SetToolPropertySourceEnabled ( MultiTextureProps , true ) ;
break ;
default :
break ;
}
2020-06-23 18:40:00 -04:00
}
2020-09-01 14:07:48 -04:00
2021-06-03 15:29:38 -04:00
ResultTypes = GetMapTypesArray ( Settings - > MapTypes ) ;
Settings - > Result . Empty ( ) ;
Settings - > Result . SetNum ( ResultTypes . Num ( ) ) ;
// Generate a map between EBakeMapType and CachedMaps
CachedMapIndices . Empty ( ) ;
int32 CachedMapIdx = 0 ;
// Use the processed bitfield which may contain additional targets
// (ex. AO if BentNormal was requested).
const EBakeMapType BakeMapTypes = GetMapTypes ( Settings - > MapTypes ) ;
for ( EBakeMapType MapType : ALL_BAKE_MAP_TYPES )
{
if ( MapType = = EBakeMapType : : Occlusion )
{
if ( ( bool ) ( BakeMapTypes & EBakeMapType : : AmbientOcclusion ) )
{
CachedMapIndices . Add ( EBakeMapType : : AmbientOcclusion , CachedMapIdx + + ) ;
}
if ( ( bool ) ( BakeMapTypes & EBakeMapType : : BentNormal ) )
{
CachedMapIndices . Add ( EBakeMapType : : BentNormal , CachedMapIdx + + ) ;
}
}
else if ( ( bool ) ( BakeMapTypes & MapType ) )
{
CachedMapIndices . Add ( MapType , CachedMapIdx + + ) ;
}
}
CachedMaps . Empty ( ) ;
CachedMaps . SetNum ( CachedMapIndices . Num ( ) ) ;
2020-06-23 18:40:00 -04:00
}
2021-05-17 16:01:01 -04:00
void UBakeMeshAttributeMapsTool : : OnMapsUpdated ( const TUniquePtr < FMeshMapBaker > & NewResult )
2021-04-12 17:10:46 -04:00
{
2021-06-09 18:10:23 -04:00
FImageDimensions BakeDimensions = NewResult - > GetDimensions ( ) ;
int32 NumBakers = NewResult - > NumBakers ( ) ;
for ( int32 BakerIdx = 0 ; BakerIdx < NumBakers ; + + BakerIdx )
2021-04-12 17:10:46 -04:00
{
2021-06-09 18:10:23 -04:00
FMeshMapEvaluator * Baker = NewResult - > GetBaker ( BakerIdx ) ;
auto UpdateCachedMap = [ this , & NewResult , & BakerIdx , & BakeDimensions ] ( const EBakeMapType BakeMapType , const FTexture2DBuilder : : ETextureType TexType , const int32 ResultIdx ) - > void
2021-06-03 15:29:38 -04:00
{
FTexture2DBuilder TextureBuilder ;
2021-06-09 18:10:23 -04:00
TextureBuilder . Initialize ( TexType , BakeDimensions ) ;
TextureBuilder . Copy ( * NewResult - > GetBakeResults ( BakerIdx ) [ ResultIdx ] ) ;
2021-06-03 15:29:38 -04:00
TextureBuilder . Commit ( false ) ;
2021-06-09 18:10:23 -04:00
// The CachedMap & CachedMapIndices can be thrown out of sync if updated during
// a background compute. Validate the computed type against our cached maps.
if ( CachedMapIndices . Contains ( BakeMapType ) )
{
CachedMaps [ CachedMapIndices [ BakeMapType ] ] = TextureBuilder . GetTexture2D ( ) ;
}
} ;
switch ( Baker - > Type ( ) )
{
case EMeshMapEvaluatorType : : Normal :
{
UpdateCachedMap ( EBakeMapType : : TangentSpaceNormalMap , FTexture2DBuilder : : ETextureType : : NormalMap , 0 ) ;
2021-06-03 15:29:38 -04:00
break ;
}
2021-06-09 18:10:23 -04:00
case EMeshMapEvaluatorType : : Occlusion :
2021-06-03 15:29:38 -04:00
{
2021-06-09 18:10:23 -04:00
// Occlusion Evaluator always outputs AmbientOcclusion then BentNormal.
FMeshOcclusionMapEvaluator * OcclusionBaker = static_cast < FMeshOcclusionMapEvaluator * > ( Baker ) ;
2021-06-03 15:29:38 -04:00
int32 OcclusionIdx = 0 ;
2021-06-09 18:10:23 -04:00
if ( ( bool ) ( OcclusionBaker - > OcclusionType & EMeshOcclusionMapType : : AmbientOcclusion ) )
2021-06-03 15:29:38 -04:00
{
2021-06-09 18:10:23 -04:00
UpdateCachedMap ( EBakeMapType : : AmbientOcclusion , FTexture2DBuilder : : ETextureType : : AmbientOcclusion , OcclusionIdx + + ) ;
2021-06-03 15:29:38 -04:00
}
2021-06-09 18:10:23 -04:00
if ( ( bool ) ( OcclusionBaker - > OcclusionType & EMeshOcclusionMapType : : BentNormal ) )
2021-06-03 15:29:38 -04:00
{
2021-06-09 18:10:23 -04:00
UpdateCachedMap ( EBakeMapType : : BentNormal , FTexture2DBuilder : : ETextureType : : NormalMap , OcclusionIdx + + ) ;
2021-06-03 15:29:38 -04:00
}
break ;
}
2021-06-09 18:10:23 -04:00
case EMeshMapEvaluatorType : : Curvature :
2021-06-03 15:29:38 -04:00
{
2021-06-09 18:10:23 -04:00
UpdateCachedMap ( EBakeMapType : : Curvature , FTexture2DBuilder : : ETextureType : : Color , 0 ) ;
2021-06-03 15:29:38 -04:00
break ;
}
2021-06-09 18:10:23 -04:00
case EMeshMapEvaluatorType : : Property :
2021-06-03 15:29:38 -04:00
{
2021-06-09 18:10:23 -04:00
FMeshPropertyMapEvaluator * PropertyBaker = static_cast < FMeshPropertyMapEvaluator * > ( Baker ) ;
EBakeMapType MapType = EBakeMapType : : None ;
switch ( PropertyBaker - > Property )
{
case EMeshPropertyMapType : : Normal :
MapType = EBakeMapType : : NormalImage ;
break ;
case EMeshPropertyMapType : : FacetNormal :
MapType = EBakeMapType : : FaceNormalImage ;
break ;
case EMeshPropertyMapType : : Position :
MapType = EBakeMapType : : PositionImage ;
break ;
case EMeshPropertyMapType : : MaterialID :
MapType = EBakeMapType : : MaterialID ;
break ;
case EMeshPropertyMapType : : UVPosition :
default :
break ;
}
UpdateCachedMap ( MapType , FTexture2DBuilder : : ETextureType : : Color , 0 ) ;
2021-06-03 15:29:38 -04:00
break ;
}
2021-06-09 18:10:23 -04:00
case EMeshMapEvaluatorType : : ResampleImage :
2021-06-03 15:29:38 -04:00
{
2021-06-09 18:10:23 -04:00
UpdateCachedMap ( EBakeMapType : : Texture2DImage , FTexture2DBuilder : : ETextureType : : Color , 0 ) ;
break ;
}
case EMeshMapEvaluatorType : : MultiResampleImage :
{
UpdateCachedMap ( EBakeMapType : : MultiTexture , FTexture2DBuilder : : ETextureType : : Color , 0 ) ;
2021-06-03 15:29:38 -04:00
break ;
}
}
2021-04-12 17:10:46 -04:00
}
UpdateVisualization ( ) ;
GetToolManager ( ) - > PostInvalidation ( ) ;
}
2020-06-23 18:40:00 -04:00
2021-06-03 15:29:38 -04:00
EBakeMapType UBakeMeshAttributeMapsTool : : GetMapTypes ( const int32 & MapTypes ) const
{
EBakeMapType OutMapTypes = ( EBakeMapType ) MapTypes & EBakeMapType : : All ;
// Force AO bake for BentNormal preview
if ( ( bool ) ( OutMapTypes & EBakeMapType : : BentNormal ) )
{
OutMapTypes | = EBakeMapType : : AmbientOcclusion ;
}
return OutMapTypes ;
}
TArray < EBakeMapType > UBakeMeshAttributeMapsTool : : GetMapTypesArray ( const int32 & MapTypes ) const
{
TArray < EBakeMapType > OutMapTypes ;
int32 Bitfield = MapTypes & ( int32 ) EBakeMapType : : All ;
for ( int32 BitIdx = 0 ; Bitfield ; Bitfield > > = 1 , + + BitIdx )
{
if ( Bitfield & 1 )
{
OutMapTypes . Add ( ( EBakeMapType ) ( 1 < < BitIdx ) ) ;
}
}
return OutMapTypes ;
}
2020-06-23 18:40:00 -04:00
void UBakeMeshAttributeMapsTool : : InitializeEmptyMaps ( )
{
FTexture2DBuilder NormalsBuilder ;
NormalsBuilder . Initialize ( FTexture2DBuilder : : ETextureType : : NormalMap , FImageDimensions ( 16 , 16 ) ) ;
NormalsBuilder . Commit ( false ) ;
EmptyNormalMap = NormalsBuilder . GetTexture2D ( ) ;
2020-09-01 14:07:48 -04:00
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 ( ) ;
2020-06-23 18:40:00 -04:00
}
# undef LOCTEXT_NAMESPACE