Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Private/MeshPaintRendering.cpp
2025-05-18 13:04:45 +08:00

386 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*================================================================================
MeshPaintRendering.cpp: Mesh texture paint brush rendering
================================================================================*/
#include "MeshPaintRendering.h"
#include "ShaderParameters.h"
#include "DataDrivenShaderPlatformInfo.h"
#include "Shader.h"
#include "StaticBoundShaderState.h"
#include "RHIStaticStates.h"
#include "BatchedElements.h"
#include "GlobalShader.h"
#include "ShaderParameterUtils.h"
#include "TextureResource.h"
#include "Engine/TextureRenderTarget2D.h"
#include "PipelineStateCache.h"
namespace MeshPaintRendering
{
/** Mesh paint vertex shader */
class TMeshPaintVertexShader : public FGlobalShader
{
DECLARE_SHADER_TYPE( TMeshPaintVertexShader, Global );
public:
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && !IsConsolePlatform(Parameters.Platform);
}
/** Default constructor. */
TMeshPaintVertexShader() {}
/** Initialization constructor. */
TMeshPaintVertexShader( const ShaderMetaType::CompiledShaderInitializerType& Initializer )
: FGlobalShader( Initializer )
{
TransformParameter.Bind( Initializer.ParameterMap, TEXT( "c_Transform" ) );
}
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FMatrix44f& InTransform )
{
SetShaderValue(BatchedParameters, TransformParameter, InTransform );
}
private:
LAYOUT_FIELD(FShaderParameter, TransformParameter);
};
IMPLEMENT_SHADER_TYPE( , TMeshPaintVertexShader, TEXT( "/Engine/Private/MeshPaintVertexShader.usf" ), TEXT( "Main" ), SF_Vertex);
/** Mesh paint pixel shader */
class TMeshPaintPixelShader : public FGlobalShader
{
DECLARE_SHADER_TYPE( TMeshPaintPixelShader, Global );
public:
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && !IsConsolePlatform(Parameters.Platform);
}
/** Default constructor. */
TMeshPaintPixelShader() {}
/** Initialization constructor. */
TMeshPaintPixelShader( const ShaderMetaType::CompiledShaderInitializerType& Initializer )
: FGlobalShader( Initializer )
{
CloneTextureParameter.Bind( Initializer.ParameterMap, TEXT( "s_CloneTexture" ) );
CloneTextureParameterSampler.Bind( Initializer.ParameterMap, TEXT( "s_CloneTextureSampler" ));
WorldToBrushMatrixParameter.Bind( Initializer.ParameterMap, TEXT( "c_WorldToBrushMatrix" ) );
BrushMetricsParameter.Bind( Initializer.ParameterMap, TEXT( "c_BrushMetrics" ) );
BrushStrengthParameter.Bind( Initializer.ParameterMap, TEXT( "c_BrushStrength" ) );
BrushColorParameter.Bind( Initializer.ParameterMap, TEXT( "c_BrushColor" ) );
ChannelFlagsParameter.Bind( Initializer.ParameterMap, TEXT( "c_ChannelFlags") );
GenerateMaskFlagParameter.Bind( Initializer.ParameterMap, TEXT( "c_GenerateMaskFlag") );
GammaParameter.Bind( Initializer.ParameterMap, TEXT( "c_Gamma" ) );
PaintBrushTextureParameter.Bind(Initializer.ParameterMap, TEXT("s_PaintBrushTexture"));
PaintBrushTextureParameterSampler.Bind(Initializer.ParameterMap, TEXT("s_PaintBrushTextureSampler"));
RotationDirectionParameter.Bind(Initializer.ParameterMap, TEXT("RotationDirection"));
RotationOffsetParameter.Bind(Initializer.ParameterMap, TEXT("RotationOffset"));
}
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const float InGamma, const FMeshPaintShaderParameters& InShaderParams )
{
SetTextureParameter(
BatchedParameters,
CloneTextureParameter,
CloneTextureParameterSampler,
TStaticSamplerState< SF_Point, AM_Clamp, AM_Clamp, AM_Clamp >::GetRHI(),
InShaderParams.CloneTexture->GetRenderTargetResource()->TextureRHI );
SetShaderValue(BatchedParameters, WorldToBrushMatrixParameter, (FMatrix44f)InShaderParams.WorldToBrushMatrix );
FVector4f BrushMetrics;
BrushMetrics.X = InShaderParams.BrushRadius;
BrushMetrics.Y = InShaderParams.BrushRadialFalloffRange;
BrushMetrics.Z = InShaderParams.BrushDepth;
BrushMetrics.W = InShaderParams.BrushDepthFalloffRange;
SetShaderValue(BatchedParameters, BrushMetricsParameter, BrushMetrics );
FVector4f BrushStrength4( InShaderParams.BrushStrength, 0.0f, 0.0f, 0.0f );
SetShaderValue(BatchedParameters, BrushStrengthParameter, BrushStrength4 );
SetShaderValue(BatchedParameters, BrushColorParameter, InShaderParams.BrushColor );
FVector4f ChannelFlags;
ChannelFlags.X = InShaderParams.RedChannelFlag;
ChannelFlags.Y = InShaderParams.GreenChannelFlag;
ChannelFlags.Z = InShaderParams.BlueChannelFlag;
ChannelFlags.W = InShaderParams.AlphaChannelFlag;
SetShaderValue(BatchedParameters, ChannelFlagsParameter, ChannelFlags );
float MaskVal = InShaderParams.GenerateMaskFlag ? 1.0f : 0.0f;
SetShaderValue(BatchedParameters, GenerateMaskFlagParameter, MaskVal );
// @todo MeshPaint
SetShaderValue(BatchedParameters, GammaParameter, InGamma );
if (InShaderParams.PaintBrushTexture)
{
SetTextureParameter(
BatchedParameters,
PaintBrushTextureParameter,
PaintBrushTextureParameterSampler,
TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
InShaderParams.PaintBrushTexture->GetRenderTargetResource()->TextureRHI);
SetShaderValue(BatchedParameters, RotationOffsetParameter, InShaderParams.PaintBrushRotationOffset);
if (InShaderParams.bRotateBrushTowardsDirection)
{
SetShaderValue(BatchedParameters, RotationDirectionParameter, InShaderParams.PaintBrushDirectionVector);
}
}
}
class FMeshPaintUsePaintBrush : SHADER_PERMUTATION_BOOL("MESH_PAINT_USE_PAINTBRUSH");
class FMeshPaintUseRotateTowardDirection : SHADER_PERMUTATION_BOOL("MESH_PAINT_ROTATE_TOWARD_DIRECTION");
class FMeshPaintUseFillBucket : SHADER_PERMUTATION_BOOL("MESH_PAINT_USE_FILL_BUCKET");
using FPermutationDomain = TShaderPermutationDomain<FMeshPaintUsePaintBrush, FMeshPaintUseRotateTowardDirection, FMeshPaintUseFillBucket>;
LAYOUT_FIELD(FShaderResourceParameter, PaintBrushTextureParameter);
LAYOUT_FIELD(FShaderResourceParameter, PaintBrushTextureParameterSampler);
LAYOUT_FIELD(FShaderParameter, RotationDirectionParameter);
LAYOUT_FIELD(FShaderParameter, RotationOffsetParameter);
private:
/** Texture that is a clone of the destination render target before we start drawing */
LAYOUT_FIELD(FShaderResourceParameter, CloneTextureParameter);
LAYOUT_FIELD(FShaderResourceParameter, CloneTextureParameterSampler);
/** Brush -> World matrix */
LAYOUT_FIELD(FShaderParameter, WorldToBrushMatrixParameter);
/** Brush metrics: x = radius, y = falloff range, z = depth, w = depth falloff range */
LAYOUT_FIELD(FShaderParameter, BrushMetricsParameter);
/** Brush strength */
LAYOUT_FIELD(FShaderParameter, BrushStrengthParameter);
/** Brush color */
LAYOUT_FIELD(FShaderParameter, BrushColorParameter);
/** Flags that control paining individual channels: x = Red, y = Green, z = Blue, w = Alpha */
LAYOUT_FIELD(FShaderParameter, ChannelFlagsParameter);
/** Flag to control brush mask generation or paint blending */
LAYOUT_FIELD(FShaderParameter, GenerateMaskFlagParameter);
/** Gamma */
// @todo MeshPaint: Remove this?
LAYOUT_FIELD(FShaderParameter, GammaParameter);
};
IMPLEMENT_SHADER_TYPE( , TMeshPaintPixelShader, TEXT( "/Engine/Private/MeshPaintPixelShader.usf" ), TEXT( "Main" ), SF_Pixel );
/** Mesh paint dilate vertex shader */
class TMeshPaintDilateVertexShader : public FGlobalShader
{
DECLARE_SHADER_TYPE( TMeshPaintDilateVertexShader, Global );
public:
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && !IsConsolePlatform(Parameters.Platform);
}
/** Default constructor. */
TMeshPaintDilateVertexShader() {}
/** Initialization constructor. */
TMeshPaintDilateVertexShader( const ShaderMetaType::CompiledShaderInitializerType& Initializer )
: FGlobalShader( Initializer )
{
TransformParameter.Bind( Initializer.ParameterMap, TEXT( "c_Transform" ) );
}
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FMatrix44f& InTransform )
{
SetShaderValue(BatchedParameters, TransformParameter, InTransform );
}
private:
LAYOUT_FIELD(FShaderParameter, TransformParameter);
};
IMPLEMENT_SHADER_TYPE( , TMeshPaintDilateVertexShader, TEXT( "/Engine/Private/meshpaintdilatevertexshader.usf" ), TEXT( "Main" ), SF_Vertex );
/** Mesh paint pixel shader */
class TMeshPaintDilatePixelShader : public FGlobalShader
{
DECLARE_SHADER_TYPE( TMeshPaintDilatePixelShader, Global );
public:
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && !IsConsolePlatform(Parameters.Platform);
}
/** Default constructor. */
TMeshPaintDilatePixelShader() {}
/** Initialization constructor. */
TMeshPaintDilatePixelShader( const ShaderMetaType::CompiledShaderInitializerType& Initializer )
: FGlobalShader( Initializer )
{
Texture0Parameter.Bind( Initializer.ParameterMap, TEXT( "Texture0" ) );
Texture0ParameterSampler.Bind( Initializer.ParameterMap, TEXT( "Texture0Sampler" ) );
Texture1Parameter.Bind( Initializer.ParameterMap, TEXT( "Texture1") );
Texture1ParameterSampler.Bind( Initializer.ParameterMap, TEXT( "Texture1Sampler") );
Texture2Parameter.Bind( Initializer.ParameterMap, TEXT( "Texture2") );
Texture2ParameterSampler.Bind( Initializer.ParameterMap, TEXT( "Texture2Sampler") );
WidthPixelOffsetParameter.Bind( Initializer.ParameterMap, TEXT( "WidthPixelOffset") );
HeightPixelOffsetParameter.Bind( Initializer.ParameterMap, TEXT( "HeightPixelOffset") );
GammaParameter.Bind( Initializer.ParameterMap, TEXT( "Gamma" ) );
}
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const float InGamma, const FMeshPaintDilateShaderParameters& InShaderParams )
{
SetTextureParameter(
BatchedParameters,
Texture0Parameter,
Texture0ParameterSampler,
TStaticSamplerState< SF_Point, AM_Clamp, AM_Clamp, AM_Clamp >::GetRHI(),
InShaderParams.Texture0->GetRenderTargetResource()->TextureRHI );
SetTextureParameter(
BatchedParameters,
Texture1Parameter,
Texture1ParameterSampler,
TStaticSamplerState< SF_Point, AM_Clamp, AM_Clamp, AM_Clamp >::GetRHI(),
InShaderParams.Texture1->GetRenderTargetResource()->TextureRHI );
SetTextureParameter(
BatchedParameters,
Texture2Parameter,
Texture2ParameterSampler,
TStaticSamplerState< SF_Point, AM_Clamp, AM_Clamp, AM_Clamp >::GetRHI(),
InShaderParams.Texture2->GetRenderTargetResource()->TextureRHI );
SetShaderValue(BatchedParameters, WidthPixelOffsetParameter, InShaderParams.WidthPixelOffset );
SetShaderValue(BatchedParameters, HeightPixelOffsetParameter, InShaderParams.HeightPixelOffset );
SetShaderValue(BatchedParameters, GammaParameter, InGamma );
}
private:
/** Texture0 */
LAYOUT_FIELD(FShaderResourceParameter, Texture0Parameter);
LAYOUT_FIELD(FShaderResourceParameter, Texture0ParameterSampler);
/** Texture1 */
LAYOUT_FIELD(FShaderResourceParameter, Texture1Parameter);
LAYOUT_FIELD(FShaderResourceParameter, Texture1ParameterSampler);
/** Texture2 */
LAYOUT_FIELD(FShaderResourceParameter, Texture2Parameter);
LAYOUT_FIELD(FShaderResourceParameter, Texture2ParameterSampler);
/** Pixel size width */
LAYOUT_FIELD(FShaderParameter, WidthPixelOffsetParameter);
/** Pixel size height */
LAYOUT_FIELD(FShaderParameter, HeightPixelOffsetParameter);
/** Gamma */
// @todo MeshPaint: Remove this?
LAYOUT_FIELD(FShaderParameter, GammaParameter);
};
IMPLEMENT_SHADER_TYPE( , TMeshPaintDilatePixelShader, TEXT( "/Engine/Private/meshpaintdilatepixelshader.usf" ), TEXT( "Main" ), SF_Pixel );
/** Mesh paint vertex format */
typedef FSimpleElementVertex FMeshPaintVertex;
/** Mesh paint vertex declaration resource */
typedef FSimpleElementVertexDeclaration FMeshPaintVertexDeclaration;
/** Global mesh paint vertex declaration resource */
TGlobalResource< FMeshPaintVertexDeclaration > GMeshPaintVertexDeclaration;
typedef FSimpleElementVertex FMeshPaintDilateVertex;
typedef FSimpleElementVertexDeclaration FMeshPaintDilateVertexDeclaration;
TGlobalResource< FMeshPaintDilateVertexDeclaration > GMeshPaintDilateVertexDeclaration;
/** Binds the mesh paint vertex and pixel shaders to the graphics device */
void SetMeshPaintShaders(FRHICommandList& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, ERHIFeatureLevel::Type InFeatureLevel, const FMatrix& InTransform,
const float InGamma,
const FMeshPaintShaderParameters& InShaderParams )
{
TShaderMapRef< TMeshPaintVertexShader > VertexShader(GetGlobalShaderMap(InFeatureLevel));
TMeshPaintPixelShader::FPermutationDomain MeshPaintPermutationVector;
MeshPaintPermutationVector.Set<TMeshPaintPixelShader::FMeshPaintUsePaintBrush>(InShaderParams.PaintBrushTexture != nullptr);
MeshPaintPermutationVector.Set<TMeshPaintPixelShader::FMeshPaintUseRotateTowardDirection>(InShaderParams.bRotateBrushTowardsDirection);
MeshPaintPermutationVector.Set<TMeshPaintPixelShader::FMeshPaintUseFillBucket>(InShaderParams.bUseFillBucket);
TShaderMapRef<TMeshPaintPixelShader> PixelShader(GetGlobalShaderMap(InFeatureLevel), MeshPaintPermutationVector);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GMeshPaintVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
// Set vertex shader parameters
SetShaderParametersLegacyVS(RHICmdList, VertexShader, FMatrix44f(InTransform) ); // LWC_TODO: Precision loss
// Set pixel shader parameters
SetShaderParametersLegacyPS(RHICmdList, PixelShader, InGamma, InShaderParams );
// @todo MeshPaint: Make sure blending/color writes are setup so we can write to ALPHA if needed!
}
/** Binds the mesh paint vertex and pixel shaders to the graphics device */
void SetMeshPaintDilateShaders(FRHICommandList& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, ERHIFeatureLevel::Type InFeatureLevel, const FMatrix& InTransform,
const float InGamma,
const FMeshPaintDilateShaderParameters& InShaderParams )
{
TShaderMapRef< TMeshPaintDilateVertexShader > VertexShader(GetGlobalShaderMap(InFeatureLevel));
TShaderMapRef< TMeshPaintDilatePixelShader > PixelShader(GetGlobalShaderMap(InFeatureLevel));
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GMeshPaintDilateVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
// Set vertex shader parameters
SetShaderParametersLegacyVS(RHICmdList, VertexShader, FMatrix44f(InTransform) ); // LWC_TODO: Precision loss
// Set pixel shader parameters
SetShaderParametersLegacyPS(RHICmdList, PixelShader, InGamma, InShaderParams );
}
}