Files
UnrealEngine/Engine/Plugins/Experimental/MeshModelingToolsetExp/Source/MeshModelingToolsExp/Public/BakeMeshAttributeToolCommon.h
2025-05-18 13:04:45 +08:00

514 lines
18 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Engine/Texture2D.h"
#include "MultiSelectionTool.h"
#include "Image/ImageBuilder.h"
#include "Image/ImageDimensions.h"
#include "BakeMeshAttributeToolCommon.generated.h"
// Pre-declarations
using UE::Geometry::FImageDimensions;
using UE::Geometry::TImageBuilder;
class UStaticMesh;
class USkeletalMesh;
/**
* Bake tool property sets
*/
UENUM()
enum class EBakeNormalSpace
{
/** Tangent space */
Tangent,
/** Object space */
Object
};
UCLASS(MinimalAPI)
class UBakeInputMeshProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Target mesh to sample to */
UPROPERTY(VisibleAnywhere, Category = BakeInput, DisplayName = "Target Mesh", meta = (TransientToolProperty,
EditCondition = "TargetStaticMesh != nullptr", EditConditionHides))
TObjectPtr<UStaticMesh> TargetStaticMesh = nullptr;
/** Target mesh to sample to */
UPROPERTY(VisibleAnywhere, Category = BakeInput, DisplayName = "Target Mesh", meta = (TransientToolProperty,
EditCondition = "TargetSkeletalMesh != nullptr", EditConditionHides))
TObjectPtr<USkeletalMesh> TargetSkeletalMesh = nullptr;
/** Target mesh to sample to */
UPROPERTY(VisibleAnywhere, Category = BakeInput, DisplayName = "Target Mesh", meta = (TransientToolProperty,
EditCondition = "TargetDynamicMesh != nullptr", EditConditionHides))
TObjectPtr<AActor> TargetDynamicMesh = nullptr;
/** UV channel to use for the target mesh */
UPROPERTY(EditAnywhere, Category = BakeInput, meta = (DisplayName = "Target Mesh UV Channel",
GetOptions = GetTargetUVLayerNamesFunc, TransientToolProperty, NoResetToDefault,
EditCondition = "bHasTargetUVLayer == true", EditConditionHides, HideEditConditionToggle))
FString TargetUVLayer;
/** If true, expose the TargetUVLayer property */
UPROPERTY()
bool bHasTargetUVLayer = false;
/** Source mesh to sample from */
UPROPERTY(VisibleAnywhere, Category = BakeInput, DisplayName = "Source Mesh", meta = (TransientToolProperty,
EditCondition = "SourceStaticMesh != nullptr", EditConditionHides))
TObjectPtr<UStaticMesh> SourceStaticMesh = nullptr;
/** Source mesh to sample from */
UPROPERTY(VisibleAnywhere, Category = BakeInput, DisplayName = "Source Mesh", meta = (TransientToolProperty,
EditCondition = "SourceSkeletalMesh != nullptr", EditConditionHides))
TObjectPtr<USkeletalMesh> SourceSkeletalMesh = nullptr;
/** Source mesh to sample from */
UPROPERTY(VisibleAnywhere, Category = BakeInput, DisplayName = "Source Mesh", meta = (TransientToolProperty,
EditCondition = "SourceDynamicMesh != nullptr", EditConditionHides))
TObjectPtr<AActor> SourceDynamicMesh = nullptr;
/** If true, hide the source mesh */
UPROPERTY(EditAnywhere, Category = BakeInput, meta = (EditConditionHides, HideEditConditionToggle,
EditCondition = "SourceStaticMesh != nullptr || SourceSkeletalMesh != nullptr || SourceDynamicMesh != nullptr"))
bool bHideSourceMesh = false;
/** Source mesh normal map; if empty, the geometric normals will be used */
UPROPERTY(EditAnywhere, Category = BakeInput, AdvancedDisplay, meta = (TransientToolProperty,
EditCondition = "bHasSourceNormalMap == true", EditConditionHides, HideEditConditionToggle))
TObjectPtr<UTexture2D> SourceNormalMap = nullptr;
/** UV channel to use for the source mesh normal map; only relevant if a source normal map is set */
UPROPERTY(EditAnywhere, Category = BakeInput, AdvancedDisplay, meta = (DisplayName = "Source Normal UV Channel",
GetOptions = GetSourceUVLayerNamesFunc, TransientToolProperty, NoResetToDefault,
EditCondition = "bHasSourceNormalMap == true", EditConditionHides, HideEditConditionToggle))
FString SourceNormalMapUVLayer;
/** Normal space of the source mesh normal map. */
UPROPERTY(EditAnywhere, Category = BakeInput, AdvancedDisplay, meta = (TransientToolProperty,
EditCondition = "bHasSourceNormalMap == true", EditConditionHides, HideEditConditionToggle))
EBakeNormalSpace SourceNormalSpace = EBakeNormalSpace::Tangent;
/** If true, expose the SourceNormalMap and SourceNormalMapUVLayer properties */
UPROPERTY()
bool bHasSourceNormalMap = false;
/** Maximum allowed distance for the projection from target mesh to source mesh for the sample to be considered valid.
* This is only relevant if a separate source mesh is provided. */
UPROPERTY(EditAnywhere, Category = BakeInput, meta = (ClampMin = "0.001",
EditCondition = "SourceStaticMesh != nullptr || SourceSkeletalMesh != nullptr || SourceDynamicMesh != nullptr", HideEditConditionToggle))
float ProjectionDistance = 3.0;
/** If true, uses the world space positions for the projection from target mesh to source mesh, otherwise it uses their object space positions.
* This is only relevant if a separate source mesh is provided. */
UPROPERTY(EditAnywhere, Category = BakeInput, meta = (
EditCondition = "SourceStaticMesh != nullptr || SourceSkeletalMesh != nullptr || SourceDynamicMesh != nullptr", HideEditConditionToggle))
bool bProjectionInWorldSpace = false;
UFUNCTION()
const TArray<FString>& GetTargetUVLayerNamesFunc() const
{
return TargetUVLayerNamesList;
}
UPROPERTY(meta = (TransientToolProperty))
TArray<FString> TargetUVLayerNamesList;
UFUNCTION()
const TArray<FString>& GetSourceUVLayerNamesFunc() const
{
return SourceUVLayerNamesList;
}
UPROPERTY(meta = (TransientToolProperty))
TArray<FString> SourceUVLayerNamesList;
};
UCLASS(MinimalAPI)
class UBakeNormalMapToolProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
};
UCLASS(MinimalAPI)
class UBakeOcclusionMapToolProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Number of occlusion rays per sample */
UPROPERTY(EditAnywhere, Category = OcclusionOutput, meta = (UIMin = "1", UIMax = "1024", ClampMin = "1", ClampMax = "65536"))
int32 OcclusionRays = 16;
/** Maximum distance for occlusion rays to test for intersections; a value of 0 means infinity */
UPROPERTY(EditAnywhere, Category = OcclusionOutput, meta = (UIMin = "0.0", UIMax = "1000.0", ClampMin = "0.0", ClampMax = "99999999.0"))
float MaxDistance = 0.0f;
/** Maximum spread angle in degrees for occlusion rays; for example, 180 degrees will cover the entire hemisphere whereas 90 degrees will only cover the center of the hemisphere down to 45 degrees from the horizon. */
UPROPERTY(EditAnywhere, Category = OcclusionOutput, meta = (UIMin = "0", UIMax = "180.0", ClampMin = "0", ClampMax = "180.0"))
float SpreadAngle = 180.0f;
/** Angle in degrees from the horizon for occlusion rays for which the contribution is attenuated to reduce faceting artifacts. */
UPROPERTY(EditAnywhere, Category = OcclusionOutput, meta = (UIMin = "0", UIMax = "45.0", ClampMin = "0", ClampMax = "89.9"))
float BiasAngle = 15.0f;
/** Normal space for Bent Normal bakes. */
UPROPERTY(EditAnywhere, Category = OcclusionOutput)
EBakeNormalSpace NormalSpace = EBakeNormalSpace::Tangent;
};
UENUM()
enum class EBakeCurvatureTypeMode
{
/** Average of the minimum and maximum principal curvatures */
MeanAverage UMETA(DisplayName = "Mean"),
/** Maximum principal curvature */
Max,
/** Minimum principal curvature */
Min,
/** Product of the minimum and maximum principal curvatures */
Gaussian
};
UENUM()
enum class EBakeCurvatureColorMode
{
/** Map curvature values to grayscale such that black is negative, grey is zero, and white is positive */
Grayscale,
/** Map curvature values to red and blue such that red is negative, black is zero, and blue is positive */
RedBlue,
/** Map curvature values to red, green, blue such that red is negative, green is zero, and blue is positive */
RedGreenBlue
};
UENUM()
enum class EBakeCurvatureClampMode
{
/** Include both negative and positive curvatures */
None,
/** Clamp negative curvatures to zero */
OnlyPositive,
/** Clamp positive curvatures to zero */
OnlyNegative
};
UCLASS(MinimalAPI)
class UBakeCurvatureMapToolProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Type of curvature */
UPROPERTY(EditAnywhere, Category = CurvatureOutput)
EBakeCurvatureTypeMode CurvatureType = EBakeCurvatureTypeMode::MeanAverage;
/** How to map calculated curvature values to colors */
UPROPERTY(EditAnywhere, Category = CurvatureOutput)
EBakeCurvatureColorMode ColorMapping = EBakeCurvatureColorMode::Grayscale;
/** Multiplier for how the curvature values fill the available range in the selected Color Mapping; a larger value means that higher curvature is required to achieve the maximum color value. */
UPROPERTY(EditAnywhere, Category = CurvatureOutput, meta = (UIMin = "0.1", UIMax = "2.0", ClampMin = "0.001", ClampMax = "100.0"))
float ColorRangeMultiplier = 1.0;
/** Minimum for the curvature values to not be clamped to zero relative to the curvature for the maximum color value; a larger value means that higher curvature is required to not be considered as no curvature. */
UPROPERTY(EditAnywhere, Category = CurvatureOutput, AdvancedDisplay, meta = (DisplayName = "Color Range Minimum", UIMin = "0.0", UIMax = "1.0"))
float MinRangeMultiplier = 0.0;
/** Clamping applied to curvature values before color mapping */
UPROPERTY(EditAnywhere, Category = CurvatureOutput)
EBakeCurvatureClampMode Clamping = EBakeCurvatureClampMode::None;
};
UCLASS(MinimalAPI)
class UBakeUVShellMapToolProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** The source mesh UV Layer to sample. */
UPROPERTY(EditAnywhere, Category = "UV Shell Output")
int UVLayer = 0;
/** The thickness of the wireframe in pixels. */
UPROPERTY(EditAnywhere, Category = "UV Shell Output")
float WireframeThickness = 1.0f;
/** The color of wireframe pixels. */
UPROPERTY(EditAnywhere, Category = "UV Shell Output")
FLinearColor WireframeColor = FLinearColor::Blue;
/** The color of the UV shell interior pixels. */
UPROPERTY(EditAnywhere, Category = "UV Shell Output")
FLinearColor ShellColor = FLinearColor::Gray;
/** The color of pixels external to UV shells. */
UPROPERTY(EditAnywhere, Category = "UV Shell Output")
FLinearColor BackgroundColor = FLinearColor(0.0f, 0.0f, 0.0f, 0.0f);
};
UENUM()
enum class EBakeHeightRangeMode
{
/** Height range defined in absolute units in object space */
Absolute,
/** Height range defined as a ratio of the maximal bounding box axis */
RelativeBounds
};
UCLASS(MinimalAPI)
class UBakeHeightMapToolProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** The coordinate space to compute height */
UPROPERTY(EditAnywhere, Category = HeightOutput)
EBakeHeightRangeMode HeightRangeMode = EBakeHeightRangeMode::Absolute;
/** The inner height map distance from the low poly mesh, in object space units. This value maps to black. */
UPROPERTY(EditAnywhere, Category = HeightOutput, meta=(EditConditionHides,EditCondition="HeightRangeMode == EBakeHeightRangeMode::Absolute", UIMin=-100.0f, UIMax=100.0f))
float InnerDistance = -1.0f;
/** The outer height map distance from the low poly mesh, in object space units. This value maps to white. */
UPROPERTY(EditAnywhere, Category = HeightOutput, meta=(EditConditionHides,EditCondition="HeightRangeMode == EBakeHeightRangeMode::Absolute", UIMin=-100.0f, UIMax=100.0f))
float OuterDistance = 1.0f;
/** The inner height map distance from the low poly mesh, as a ratio of the maximum bounding box axis. This value maps to black. */
UPROPERTY(EditAnywhere, Category = HeightOutput, meta=(EditConditionHides,EditCondition="HeightRangeMode == EBakeHeightRangeMode::RelativeBounds", ClampMin=-1.0f, ClampMax=1.0f))
float InnerBoundsDistance = -0.1f;
/** The outer height map distance from the low poly mesh, as a ratio of the maximum bounding box axis. This value maps to white. */
UPROPERTY(EditAnywhere, Category = HeightOutput, meta=(EditConditionHides,EditCondition="HeightRangeMode == EBakeHeightRangeMode::RelativeBounds", ClampMin=-1.0f, ClampMax=1.0f))
float OuterBoundsDistance = 0.1f;
};
UCLASS(MinimalAPI)
class UBakeTexture2DProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Source mesh texture that is to be resampled into a new texture */
UPROPERTY(EditAnywhere, Category = TextureOutput, meta = (TransientToolProperty))
TObjectPtr<UTexture2D> SourceTexture;
/** UV channel to use for the source mesh texture */
UPROPERTY(EditAnywhere, Category = TextureOutput, meta = (DisplayName = "Source Texture UV Channel",
GetOptions = GetUVLayerNamesFunc, NoResetToDefault))
FString UVLayer;
UFUNCTION()
const TArray<FString>& GetUVLayerNamesFunc() const
{
return UVLayerNamesList;
}
UPROPERTY(meta = (TransientToolProperty))
TArray<FString> UVLayerNamesList;
};
UCLASS(MinimalAPI)
class UBakeMultiTexture2DProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** For each material ID, the source texture that will be resampled in that material's region*/
UPROPERTY(EditAnywhere, EditFixedSize, Category = MultiTextureOutput, meta = (DisplayName = "Material IDs",
TransientToolProperty, EditFixedOrder))
TArray<TObjectPtr<UTexture2D>> MaterialIDSourceTextures;
/** UV channel to use for the source mesh texture */
UPROPERTY(EditAnywhere, Category = MultiTextureOutput, meta = (DisplayName = "Source Texture UV Channel",
GetOptions = GetUVLayerNamesFunc, NoResetToDefault))
FString UVLayer;
UFUNCTION()
const TArray<FString>& GetUVLayerNamesFunc() const
{
return UVLayerNamesList;
}
UPROPERTY(meta = (TransientToolProperty))
TArray<FString> UVLayerNamesList;
/** The set of all source textures from all input materials */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = MultiTextureOutput, meta = (DisplayName = "Source Textures",
TransientToolProperty))
TArray<TObjectPtr<UTexture2D>> AllSourceTextures;
};
UCLASS(MinimalAPI)
class UBakeVisualizationProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** Preview the texture as an input to the respective material parameter (ex. Normal, Ambient Occlusion) */
UPROPERTY(EditAnywhere, Category = Preview)
bool bPreviewAsMaterial = false;
/** Adjust the brightness of the preview material; does not affect results stored in textures */
UPROPERTY(EditAnywhere, Category = Preview, meta = (DisplayName = "Brightness", UIMin = "0.0", UIMax = "1.0"))
float Brightness = 1.0f;
/** Ambient Occlusion multiplier in the viewport; does not affect results stored in textures */
UPROPERTY(EditAnywhere, Category = Preview, meta = (DisplayName = "AO Multiplier", UIMin = "0.0", UIMax = "1.0",
ClampMin = "0.0", ClampMax = "1.0"))
float AOMultiplier = 1.0f;
};
/**
* Bake tool property settings structs
*/
struct FDetailMeshSettings
{
int32 UVLayer = 0;
EBakeNormalSpace NormalSpace = EBakeNormalSpace::Tangent;
bool operator==(const FDetailMeshSettings& Other) const
{
return UVLayer == Other.UVLayer && NormalSpace == Other.NormalSpace;
}
};
struct FNormalMapSettings
{
FImageDimensions Dimensions;
bool operator==(const FNormalMapSettings& Other) const
{
return Dimensions == Other.Dimensions;
}
};
struct FOcclusionMapSettings
{
FImageDimensions Dimensions;
int32 OcclusionRays;
float MaxDistance;
float SpreadAngle;
float BiasAngle;
EBakeNormalSpace NormalSpace = EBakeNormalSpace::Tangent;
bool operator==(const FOcclusionMapSettings& Other) const
{
return Dimensions == Other.Dimensions &&
OcclusionRays == Other.OcclusionRays &&
MaxDistance == Other.MaxDistance &&
SpreadAngle == Other.SpreadAngle &&
BiasAngle == Other.BiasAngle &&
NormalSpace == Other.NormalSpace;
}
};
struct FCurvatureMapSettings
{
FImageDimensions Dimensions;
int32 CurvatureType = 0;
float RangeMultiplier = 1.0f;
float MinRangeMultiplier = 0.0f;
int32 ColorMode = 0;
int32 ClampMode = 0;
bool operator==(const FCurvatureMapSettings& Other) const
{
return Dimensions == Other.Dimensions && CurvatureType == Other.CurvatureType && RangeMultiplier == Other.RangeMultiplier && MinRangeMultiplier == Other.MinRangeMultiplier && ColorMode == Other.ColorMode && ClampMode == Other.ClampMode;
}
};
struct FMeshPropertyMapSettings
{
FImageDimensions Dimensions;
bool operator==(const FMeshPropertyMapSettings& Other) const
{
return Dimensions == Other.Dimensions;
}
};
struct FHeightMapSettings
{
FImageDimensions Dimensions;
int32 HeightRangeMode = 0;
float InnerDistance = -1.0f;
float OuterDistance = 1.0f;
float InnerBoundsDistance = -0.1f;
float OuterBoundsDistance = 0.1f;
bool operator==(const FHeightMapSettings& Other) const
{
return Dimensions == Other.Dimensions
&& HeightRangeMode == Other.HeightRangeMode
&& InnerDistance == Other.InnerDistance
&& OuterDistance == Other.OuterDistance
&& InnerBoundsDistance == Other.InnerBoundsDistance
&& OuterBoundsDistance == Other.OuterBoundsDistance;
}
};
struct FUVShellMapSettings
{
FImageDimensions Dimensions;
int UVLayer = 0;
float WireframeThickness = 1.0f;
FLinearColor WireframeColor = FLinearColor::Blue;
FLinearColor ShellColor = FLinearColor::Gray;
FLinearColor BackgroundColor = FLinearColor(0.0f, 0.0f, 0.0f, 0.0f);
bool operator==(const FUVShellMapSettings& Other) const
{
return Dimensions == Other.Dimensions &&
UVLayer == Other.UVLayer &&
WireframeThickness == Other.WireframeThickness &&
WireframeColor == Other.WireframeColor &&
ShellColor == Other.ShellColor &&
BackgroundColor == Other.BackgroundColor;
}
};
struct FTexture2DSettings
{
FImageDimensions Dimensions;
int32 UVLayer = 0;
bool operator==(const FTexture2DSettings& Other) const
{
return Dimensions == Other.Dimensions && UVLayer == Other.UVLayer;
}
};
/**
* Bake compute state
*/
enum class EBakeOpState
{
Clean = 0, // No-op - evaluation already launched/complete.
Evaluate = 1 << 0, // Inputs are modified and valid, re-evaluate.
EvaluateDetailMesh = 1 << 1, // Detail mesh input is modified, re-evaluate the detail mesh.
Invalid = 1 << 2 // Inputs are modified and invalid - retry eval until valid.
};
ENUM_CLASS_FLAGS(EBakeOpState);