2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
/*=============================================================================
PostProcessCombineLUTs . cpp : Post processing tone mapping implementation .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "RendererPrivate.h"
# include "ScenePrivate.h"
# include "SceneFilterRendering.h"
# include "PostProcessCombineLUTs.h"
# include "PostProcessing.h"
# include "ScreenRendering.h"
2014-08-21 06:03:00 -04:00
# include "SceneUtils.h"
2014-03-14 14:13:41 -04:00
2014-06-25 05:47:33 -04:00
// CVars
static TAutoConsoleVariable < float > CVarColorMin (
TEXT ( " r.Color.Min " ) ,
0.0f ,
TEXT ( " Allows to define where the value 0 in the color channels is mapped to after color grading. \n " )
TEXT ( " The value should be around 0, positive: a gray scale is added to the darks, negative: more dark values become black, Default: 0 " ) ,
ECVF_RenderThreadSafe ) ;
static TAutoConsoleVariable < float > CVarColorMid (
TEXT ( " r.Color.Mid " ) ,
0.5f ,
TEXT ( " Allows to define where the value 0.5 in the color channels is mapped to after color grading (This is similar to a gamma correction). \n " )
TEXT ( " Value should be around 0.5, smaller values darken the mid tones, larger values brighten the mid tones, Default: 0.5 " ) ,
ECVF_RenderThreadSafe ) ;
static TAutoConsoleVariable < float > CVarColorMax (
TEXT ( " r.Color.Max " ) ,
1.0f ,
TEXT ( " Allows to define where the value 1.0 in the color channels is mapped to after color grading. \n " )
TEXT ( " Value should be around 1, smaller values darken the highlights, larger values move more colors towards white, Default: 1 " ) ,
ECVF_RenderThreadSafe ) ;
2015-04-28 15:27:19 -04:00
int32 GLUTSize = 32 ;
static FAutoConsoleVariableRef CVarLUTSize (
TEXT ( " r.LUT.Size " ) ,
GLUTSize ,
TEXT ( " Size of film LUT " ) ,
ECVF_RenderThreadSafe
) ;
2015-04-28 16:57:25 -04:00
static TAutoConsoleVariable < int32 > CVarTonemapperFilm (
TEXT ( " r.TonemapperFilm " ) ,
0 ,
TEXT ( " Use new film tone mapper " ) ,
ECVF_RenderThreadSafe
) ;
2014-03-14 14:13:41 -04:00
// false:use 256x16 texture / true:use volume texture (faster, requires geometry shader)
// USE_VOLUME_LUT: needs to be the same for C++ and HLSL
2014-05-06 11:37:57 -04:00
static bool UseVolumeTextureLUT ( EShaderPlatform Platform )
{
// @todo Mac OS X: in order to share precompiled shaders between GL 3.3 & GL 4.1 devices we mustn't use volume-texture rendering as it isn't universally supported.
2015-01-15 15:27:57 -05:00
return ( IsFeatureLevelSupported ( Platform , ERHIFeatureLevel : : SM4 ) & & GSupportsVolumeTextureRendering & & Platform ! = EShaderPlatform : : SP_OPENGL_SM4_MAC & & RHISupportsGeometryShaders ( Platform ) ) ;
2014-03-14 14:13:41 -04:00
}
// including the neutral one at index 0
const uint32 GMaxLUTBlendCount = 5 ;
struct FColorTransform
{
FColorTransform ( )
{
Reset ( ) ;
}
float MinValue ;
float MidValue ;
float MaxValue ;
void Reset ( )
{
MinValue = 0.0f ;
MidValue = 0.5f ;
MaxValue = 1.0f ;
}
} ;
/*-----------------------------------------------------------------------------
FColorRemapShaderParameters
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
FColorRemapShaderParameters : : FColorRemapShaderParameters ( const FShaderParameterMap & ParameterMap )
{
MappingPolynomial . Bind ( ParameterMap , TEXT ( " MappingPolynomial " ) ) ;
}
2014-06-10 07:29:49 -04:00
void FColorRemapShaderParameters : : Set ( FRHICommandList & RHICmdList , const FPixelShaderRHIParamRef ShaderRHI )
2014-03-14 14:13:41 -04:00
{
FColorTransform ColorTransform ;
2014-06-25 05:47:33 -04:00
ColorTransform . MinValue = FMath : : Clamp ( CVarColorMin . GetValueOnRenderThread ( ) , - 10.0f , 10.0f ) ;
ColorTransform . MidValue = FMath : : Clamp ( CVarColorMid . GetValueOnRenderThread ( ) , - 10.0f , 10.0f ) ;
ColorTransform . MaxValue = FMath : : Clamp ( CVarColorMax . GetValueOnRenderThread ( ) , - 10.0f , 10.0f ) ;
2014-03-14 14:13:41 -04:00
{
// x is the input value, y the output value
// RGB = a, b, c where y = a * x*x + b * x + c
float c = ColorTransform . MinValue ;
float b = 4 * ColorTransform . MidValue - 3 * ColorTransform . MinValue - ColorTransform . MaxValue ;
float a = ColorTransform . MaxValue - ColorTransform . MinValue - b ;
2014-06-05 16:38:54 -04:00
SetShaderValue ( RHICmdList , ShaderRHI , MappingPolynomial , FVector ( a , b , c ) ) ;
2014-03-14 14:13:41 -04:00
}
}
FArchive & operator < < ( FArchive & Ar , FColorRemapShaderParameters & P )
{
Ar < < P . MappingPolynomial ;
return Ar ;
}
/**
* A pixel shader for blending multiple LUT to one
*
* @ param BlendCount > 0
*/
template < uint32 BlendCount >
class FLUTBlenderPS : public FGlobalShader
{
DECLARE_SHADER_TYPE ( FLUTBlenderPS , Global ) ;
public :
2014-08-25 14:41:54 -04:00
static bool ShouldCache ( EShaderPlatform Platform ) { return IsFeatureLevelSupported ( Platform , ERHIFeatureLevel : : SM4 ) ; }
2014-03-14 14:13:41 -04:00
FLUTBlenderPS ( const ShaderMetaType : : CompiledShaderInitializerType & Initializer )
: FGlobalShader ( Initializer )
, ColorRemapShaderParameters ( Initializer . ParameterMap )
{
// Suppress static code analysis warnings about a potentially ill-defined loop. BlendCount > 0 is valid.
CA_SUPPRESS ( 6294 )
// starts as 1 as 0 is the neutral one
for ( uint32 i = 1 ; i < BlendCount ; + + i )
{
FString Name = FString : : Printf ( TEXT ( " Texture%d " ) , i ) ;
TextureParameter [ i ] . Bind ( Initializer . ParameterMap , * Name ) ;
TextureParameterSampler [ i ] . Bind ( Initializer . ParameterMap , * ( Name + TEXT ( " Sampler " ) ) ) ;
}
WeightsParameter . Bind ( Initializer . ParameterMap , TEXT ( " LUTWeights " ) ) ;
ColorScale . Bind ( Initializer . ParameterMap , TEXT ( " ColorScale " ) ) ;
OverlayColor . Bind ( Initializer . ParameterMap , TEXT ( " OverlayColor " ) ) ;
2015-04-28 15:27:19 -04:00
InverseGamma . Bind ( Initializer . ParameterMap , TEXT ( " InverseGamma " ) ) ;
WhiteTemp . Bind ( Initializer . ParameterMap , TEXT ( " WhiteTemp " ) ) ;
WhiteTint . Bind ( Initializer . ParameterMap , TEXT ( " WhiteTint " ) ) ;
ColorSaturation . Bind ( Initializer . ParameterMap , TEXT ( " ColorSaturation " ) ) ;
ColorContrast . Bind ( Initializer . ParameterMap , TEXT ( " ColorContrast " ) ) ;
ColorGamma . Bind ( Initializer . ParameterMap , TEXT ( " ColorGamma " ) ) ;
ColorGain . Bind ( Initializer . ParameterMap , TEXT ( " ColorGain " ) ) ;
ColorOffset . Bind ( Initializer . ParameterMap , TEXT ( " ColorOffset " ) ) ;
FilmSlope . Bind ( Initializer . ParameterMap , TEXT ( " FilmSlope " ) ) ;
FilmToe . Bind ( Initializer . ParameterMap , TEXT ( " FilmToe " ) ) ;
FilmShoulder . Bind ( Initializer . ParameterMap , TEXT ( " FilmShoulder " ) ) ;
FilmBlackClip . Bind ( Initializer . ParameterMap , TEXT ( " FilmBlackClip " ) ) ;
FilmWhiteClip . Bind ( Initializer . ParameterMap , TEXT ( " FilmWhiteClip " ) ) ;
ColorMatrixR_ColorCurveCd1 . Bind ( Initializer . ParameterMap , TEXT ( " ColorMatrixR_ColorCurveCd1 " ) ) ;
ColorMatrixG_ColorCurveCd3Cm3 . Bind ( Initializer . ParameterMap , TEXT ( " ColorMatrixG_ColorCurveCd3Cm3 " ) ) ;
ColorMatrixB_ColorCurveCm2 . Bind ( Initializer . ParameterMap , TEXT ( " ColorMatrixB_ColorCurveCm2 " ) ) ;
ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3 . Bind ( Initializer . ParameterMap , TEXT ( " ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3 " ) ) ;
ColorCurve_Ch1_Ch2 . Bind ( Initializer . ParameterMap , TEXT ( " ColorCurve_Ch1_Ch2 " ) ) ;
ColorShadow_Luma . Bind ( Initializer . ParameterMap , TEXT ( " ColorShadow_Luma " ) ) ;
ColorShadow_Tint1 . Bind ( Initializer . ParameterMap , TEXT ( " ColorShadow_Tint1 " ) ) ;
ColorShadow_Tint2 . Bind ( Initializer . ParameterMap , TEXT ( " ColorShadow_Tint2 " ) ) ;
2014-03-14 14:13:41 -04:00
}
FLUTBlenderPS ( ) { }
2014-06-10 07:29:49 -04:00
void SetParameters ( FRHICommandList & RHICmdList , const FSceneView & View , FTexture * Texture [ BlendCount ] , float Weights [ BlendCount ] )
2014-03-14 14:13:41 -04:00
{
2015-04-28 15:27:19 -04:00
const FPostProcessSettings & Settings = View . FinalPostProcessSettings ;
const FSceneViewFamily & ViewFamily = * ( View . Family ) ;
2014-03-14 14:13:41 -04:00
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader ( ) ;
for ( uint32 i = 0 ; i < BlendCount ; + + i )
{
// we don't need to set the neutral one
if ( i ! = 0 )
{
2014-06-05 16:38:54 -04:00
SetTextureParameter ( RHICmdList , ShaderRHI , TextureParameter [ i ] , TextureParameterSampler [ i ] , Texture [ i ] ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-05 16:38:54 -04:00
SetShaderValue ( RHICmdList , ShaderRHI , WeightsParameter , Weights [ i ] , i ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-05 16:38:54 -04:00
SetShaderValue ( RHICmdList , ShaderRHI , ColorScale , View . ColorScale ) ;
SetShaderValue ( RHICmdList , ShaderRHI , OverlayColor , View . OverlayColor ) ;
ColorRemapShaderParameters . Set ( RHICmdList , ShaderRHI ) ;
2015-04-28 15:27:19 -04:00
// White balance
SetShaderValue ( RHICmdList , ShaderRHI , WhiteTemp , Settings . WhiteTemp ) ;
SetShaderValue ( RHICmdList , ShaderRHI , WhiteTint , Settings . WhiteTint ) ;
// Color grade
SetShaderValue ( RHICmdList , ShaderRHI , ColorSaturation , Settings . ColorSaturation ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorContrast , Settings . ColorContrast ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorGamma , Settings . ColorGamma ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorGain , Settings . ColorGain ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorOffset , Settings . ColorOffset ) ;
// Film
SetShaderValue ( RHICmdList , ShaderRHI , FilmSlope , Settings . FilmSlope ) ;
SetShaderValue ( RHICmdList , ShaderRHI , FilmToe , Settings . FilmToe ) ;
SetShaderValue ( RHICmdList , ShaderRHI , FilmShoulder , Settings . FilmShoulder ) ;
SetShaderValue ( RHICmdList , ShaderRHI , FilmBlackClip , Settings . FilmBlackClip ) ;
SetShaderValue ( RHICmdList , ShaderRHI , FilmWhiteClip , Settings . FilmWhiteClip ) ;
{
FVector InvDisplayGammaValue ;
InvDisplayGammaValue . X = 1.0f / ViewFamily . RenderTarget - > GetDisplayGamma ( ) ;
InvDisplayGammaValue . Y = 2.2f / ViewFamily . RenderTarget - > GetDisplayGamma ( ) ;
{
static TConsoleVariableData < float > * CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataFloat ( TEXT ( " r.TonemapperGamma " ) ) ;
float Value = CVar - > GetValueOnRenderThread ( ) ;
if ( Value < 1.0f )
{
Value = 1.0f ;
}
InvDisplayGammaValue . Z = 1.0f / Value ;
}
SetShaderValue ( RHICmdList , ShaderRHI , InverseGamma , InvDisplayGammaValue ) ;
}
{
// Legacy tone mapper
// TODO remove
// Must insure inputs are in correct range (else possible generation of NaNs).
float InExposure = 1.0f ;
FVector InWhitePoint ( Settings . FilmWhitePoint ) ;
float InSaturation = FMath : : Clamp ( Settings . FilmSaturation , 0.0f , 2.0f ) ;
FVector InLuma = FVector ( 1.0f / 3.0f , 1.0f / 3.0f , 1.0f / 3.0f ) ;
FVector InMatrixR ( Settings . FilmChannelMixerRed ) ;
FVector InMatrixG ( Settings . FilmChannelMixerGreen ) ;
FVector InMatrixB ( Settings . FilmChannelMixerBlue ) ;
float InContrast = FMath : : Clamp ( Settings . FilmContrast , 0.0f , 1.0f ) + 1.0f ;
float InDynamicRange = powf ( 2.0f , FMath : : Clamp ( Settings . FilmDynamicRange , 1.0f , 4.0f ) ) ;
float InToe = ( 1.0f - FMath : : Clamp ( Settings . FilmToeAmount , 0.0f , 1.0f ) ) * 0.18f ;
InToe = FMath : : Clamp ( InToe , 0.18f / 8.0f , 0.18f * ( 15.0f / 16.0f ) ) ;
float InHeal = 1.0f - ( FMath : : Max ( 1.0f / 32.0f , 1.0f - FMath : : Clamp ( Settings . FilmHealAmount , 0.0f , 1.0f ) ) * ( 1.0f - 0.18f ) ) ;
FVector InShadowTint ( Settings . FilmShadowTint ) ;
float InShadowTintBlend = FMath : : Clamp ( Settings . FilmShadowTintBlend , 0.0f , 1.0f ) * 64.0f ;
// Shadow tint amount enables turning off shadow tinting.
float InShadowTintAmount = FMath : : Clamp ( Settings . FilmShadowTintAmount , 0.0f , 1.0f ) ;
InShadowTint = InWhitePoint + ( InShadowTint - InWhitePoint ) * InShadowTintAmount ;
// Make sure channel mixer inputs sum to 1 (+ smart dealing with all zeros).
InMatrixR . X + = 1.0f / ( 256.0f * 256.0f * 32.0f ) ;
InMatrixG . Y + = 1.0f / ( 256.0f * 256.0f * 32.0f ) ;
InMatrixB . Z + = 1.0f / ( 256.0f * 256.0f * 32.0f ) ;
InMatrixR * = 1.0f / FVector : : DotProduct ( InMatrixR , FVector ( 1.0f ) ) ;
InMatrixG * = 1.0f / FVector : : DotProduct ( InMatrixG , FVector ( 1.0f ) ) ;
InMatrixB * = 1.0f / FVector : : DotProduct ( InMatrixB , FVector ( 1.0f ) ) ;
// Conversion from linear rgb to luma (using HDTV coef).
FVector LumaWeights = FVector ( 0.2126f , 0.7152f , 0.0722f ) ;
// Make sure white point has 1.0 as luma (so adjusting white point doesn't change exposure).
// Make sure {0.0,0.0,0.0} inputs do something sane (default to white).
InWhitePoint + = FVector ( 1.0f / ( 256.0f * 256.0f * 32.0f ) ) ;
InWhitePoint * = 1.0f / FVector : : DotProduct ( InWhitePoint , LumaWeights ) ;
InShadowTint + = FVector ( 1.0f / ( 256.0f * 256.0f * 32.0f ) ) ;
InShadowTint * = 1.0f / FVector : : DotProduct ( InShadowTint , LumaWeights ) ;
// Grey after color matrix is applied.
FVector ColorMatrixLuma = FVector (
FVector : : DotProduct ( InLuma . X * FVector ( InMatrixR . X , InMatrixG . X , InMatrixB . X ) , FVector ( 1.0f ) ) ,
FVector : : DotProduct ( InLuma . Y * FVector ( InMatrixR . Y , InMatrixG . Y , InMatrixB . Y ) , FVector ( 1.0f ) ) ,
FVector : : DotProduct ( InLuma . Z * FVector ( InMatrixR . Z , InMatrixG . Z , InMatrixB . Z ) , FVector ( 1.0f ) ) ) ;
FVector OutMatrixR = FVector ( 0.0f ) ;
FVector OutMatrixG = FVector ( 0.0f ) ;
FVector OutMatrixB = FVector ( 0.0f ) ;
FVector OutColorShadow_Luma = LumaWeights * InShadowTintBlend ;
FVector OutColorShadow_Tint1 = InWhitePoint ;
FVector OutColorShadow_Tint2 = InShadowTint - InWhitePoint ;
// Final color matrix effected by saturation and exposure.
OutMatrixR = ( ColorMatrixLuma + ( ( InMatrixR - ColorMatrixLuma ) * InSaturation ) ) * InExposure ;
OutMatrixG = ( ColorMatrixLuma + ( ( InMatrixG - ColorMatrixLuma ) * InSaturation ) ) * InExposure ;
OutMatrixB = ( ColorMatrixLuma + ( ( InMatrixB - ColorMatrixLuma ) * InSaturation ) ) * InExposure ;
// Line for linear section.
float FilmLineOffset = 0.18f - 0.18f * InContrast ;
float FilmXAtY0 = - FilmLineOffset / InContrast ;
float FilmXAtY1 = ( 1.0f - FilmLineOffset ) / InContrast ;
float FilmXS = FilmXAtY1 - FilmXAtY0 ;
// Coordinates of linear section.
float FilmHiX = FilmXAtY0 + InHeal * FilmXS ;
float FilmHiY = FilmHiX * InContrast + FilmLineOffset ;
float FilmLoX = FilmXAtY0 + InToe * FilmXS ;
float FilmLoY = FilmLoX * InContrast + FilmLineOffset ;
// Supported exposure range before clipping.
float FilmHeal = InDynamicRange - FilmHiX ;
// Intermediates.
float FilmMidXS = FilmHiX - FilmLoX ;
float FilmMidYS = FilmHiY - FilmLoY ;
2015-04-28 16:57:25 -04:00
float FilmSlopeS = FilmMidYS / ( FilmMidXS ) ;
2015-04-28 15:27:19 -04:00
float FilmHiYS = 1.0f - FilmHiY ;
float FilmLoYS = FilmLoY ;
2015-04-29 05:04:33 -04:00
float FilmToeS = FilmLoX ;
2015-04-28 16:57:25 -04:00
float FilmHiG = ( - FilmHiYS + ( FilmSlopeS * FilmHeal ) ) / ( FilmSlopeS * FilmHeal ) ;
2015-04-29 05:04:33 -04:00
float FilmLoG = ( - FilmLoYS + ( FilmSlopeS * FilmToeS ) ) / ( FilmSlopeS * FilmToeS ) ;
2015-04-28 15:27:19 -04:00
// Constants.
float OutColorCurveCh1 = FilmHiYS / FilmHiG ;
float OutColorCurveCh2 = - FilmHiX * ( FilmHiYS / FilmHiG ) ;
2015-04-28 16:57:25 -04:00
float OutColorCurveCh3 = FilmHiYS / ( FilmSlopeS * FilmHiG ) - FilmHiX ;
2015-04-28 15:27:19 -04:00
float OutColorCurveCh0Cm1 = FilmHiX ;
2015-04-28 16:57:25 -04:00
float OutColorCurveCm2 = FilmSlopeS ;
2015-04-28 15:27:19 -04:00
float OutColorCurveCm0Cd0 = FilmLoX ;
2015-04-28 16:57:25 -04:00
float OutColorCurveCd3Cm3 = FilmLoY - FilmLoX * FilmSlopeS ;
2015-04-28 15:27:19 -04:00
float OutColorCurveCd1 = 0.0f ;
float OutColorCurveCd2 = 1.0f ;
// Handle these separate in case of FilmLoG being 0.
if ( FilmLoG ! = 0.0f )
{
OutColorCurveCd1 = - FilmLoYS / FilmLoG ;
2015-04-28 16:57:25 -04:00
OutColorCurveCd2 = FilmLoYS / ( FilmSlopeS * FilmLoG ) ;
2015-04-28 15:27:19 -04:00
}
else
{
// FilmLoG being zero means dark region is a linear segment (so just continue the middle section).
OutColorCurveCm0Cd0 = 0.0f ;
OutColorCurveCd3Cm3 = 0.0f ;
}
FVector4 Constants [ 8 ] ;
Constants [ 0 ] = FVector4 ( OutMatrixR , OutColorCurveCd1 ) ;
Constants [ 1 ] = FVector4 ( OutMatrixG , OutColorCurveCd3Cm3 ) ;
Constants [ 2 ] = FVector4 ( OutMatrixB , OutColorCurveCm2 ) ;
Constants [ 3 ] = FVector4 ( OutColorCurveCm0Cd0 , OutColorCurveCd2 , OutColorCurveCh0Cm1 , OutColorCurveCh3 ) ;
Constants [ 4 ] = FVector4 ( OutColorCurveCh1 , OutColorCurveCh2 , 0.0f , 0.0f ) ;
Constants [ 5 ] = FVector4 ( OutColorShadow_Luma , 0.0f ) ;
Constants [ 6 ] = FVector4 ( OutColorShadow_Tint1 , 0.0f ) ;
2015-04-28 16:57:25 -04:00
Constants [ 7 ] = FVector4 ( OutColorShadow_Tint2 , CVarTonemapperFilm . GetValueOnRenderThread ( ) ) ;
2015-04-28 15:27:19 -04:00
SetShaderValue ( RHICmdList , ShaderRHI , ColorMatrixR_ColorCurveCd1 , Constants [ 0 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorMatrixG_ColorCurveCd3Cm3 , Constants [ 1 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorMatrixB_ColorCurveCm2 , Constants [ 2 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3 , Constants [ 3 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorCurve_Ch1_Ch2 , Constants [ 4 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorShadow_Luma , Constants [ 5 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorShadow_Tint1 , Constants [ 6 ] ) ;
SetShaderValue ( RHICmdList , ShaderRHI , ColorShadow_Tint2 , Constants [ 7 ] ) ;
}
2014-03-14 14:13:41 -04:00
}
static void ModifyCompilationEnvironment ( EShaderPlatform Platform , FShaderCompilerEnvironment & OutEnvironment )
{
FGlobalShader : : ModifyCompilationEnvironment ( Platform , OutEnvironment ) ;
OutEnvironment . SetDefine ( TEXT ( " BLENDCOUNT " ) , BlendCount ) ;
2014-05-06 11:37:57 -04:00
OutEnvironment . SetDefine ( TEXT ( " USE_VOLUME_LUT " ) , UseVolumeTextureLUT ( Platform ) ) ;
2015-04-28 15:27:19 -04:00
//OutEnvironment.SetDefine(TEXT("USE_GAMMA"), OutputDevice == 1);
//OutEnvironment.SetDefine(TEXT("USE_709"), OutputDevice == 2);
2014-03-14 14:13:41 -04:00
}
2015-04-01 07:20:55 -04:00
virtual bool Serialize ( FArchive & Ar ) override
2014-03-14 14:13:41 -04:00
{
bool bShaderHasOutdatedParameters = FGlobalShader : : Serialize ( Ar ) ;
for ( uint32 i = 0 ; i < BlendCount ; + + i )
{
Ar < < TextureParameter [ i ] ;
Ar < < TextureParameterSampler [ i ] ;
}
Ar < < WeightsParameter < < ColorScale < < OverlayColor ;
Ar < < ColorRemapShaderParameters ;
2015-04-28 16:50:50 -04:00
Ar < < InverseGamma ;
2014-03-14 14:13:41 -04:00
2015-04-28 15:27:19 -04:00
Ar < < WhiteTemp ;
Ar < < WhiteTint ;
Ar < < ColorSaturation ;
Ar < < ColorContrast ;
Ar < < ColorGamma ;
Ar < < ColorGain ;
Ar < < ColorOffset ;
Ar < < FilmSlope ;
Ar < < FilmToe ;
Ar < < FilmShoulder ;
Ar < < FilmBlackClip ;
Ar < < FilmWhiteClip ;
Ar < < ColorMatrixR_ColorCurveCd1 < < ColorMatrixG_ColorCurveCd3Cm3 < < ColorMatrixB_ColorCurveCm2
< < ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3 < < ColorCurve_Ch1_Ch2 < < ColorShadow_Luma < < ColorShadow_Tint1 < < ColorShadow_Tint2 ;
2014-03-14 14:13:41 -04:00
return bShaderHasOutdatedParameters ;
}
private : // ---------------------------------------------------
// [0] is not used as it's the neutral one we do in the shader
FShaderResourceParameter TextureParameter [ GMaxLUTBlendCount ] ;
FShaderResourceParameter TextureParameterSampler [ GMaxLUTBlendCount ] ;
FShaderParameter WeightsParameter ;
FShaderParameter ColorScale ;
FShaderParameter OverlayColor ;
2015-04-28 15:27:19 -04:00
FShaderParameter InverseGamma ;
2014-03-14 14:13:41 -04:00
FColorRemapShaderParameters ColorRemapShaderParameters ;
2015-04-28 15:27:19 -04:00
FShaderParameter WhiteTemp ;
FShaderParameter WhiteTint ;
FShaderParameter ColorSaturation ;
FShaderParameter ColorContrast ;
FShaderParameter ColorGamma ;
FShaderParameter ColorGain ;
FShaderParameter ColorOffset ;
FShaderParameter FilmSlope ;
FShaderParameter FilmToe ;
FShaderParameter FilmShoulder ;
FShaderParameter FilmBlackClip ;
FShaderParameter FilmWhiteClip ;
// Legacy
FShaderParameter ColorMatrixR_ColorCurveCd1 ;
FShaderParameter ColorMatrixG_ColorCurveCd3Cm3 ;
FShaderParameter ColorMatrixB_ColorCurveCm2 ;
FShaderParameter ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3 ;
FShaderParameter ColorCurve_Ch1_Ch2 ;
FShaderParameter ColorShadow_Luma ;
FShaderParameter ColorShadow_Tint1 ;
FShaderParameter ColorShadow_Tint2 ;
2014-03-14 14:13:41 -04:00
} ;
IMPLEMENT_SHADER_TYPE ( template < > , FLUTBlenderPS < 1 > , TEXT ( " PostProcessCombineLUTs " ) , TEXT ( " MainPS " ) , SF_Pixel ) ;
IMPLEMENT_SHADER_TYPE ( template < > , FLUTBlenderPS < 2 > , TEXT ( " PostProcessCombineLUTs " ) , TEXT ( " MainPS " ) , SF_Pixel ) ;
IMPLEMENT_SHADER_TYPE ( template < > , FLUTBlenderPS < 3 > , TEXT ( " PostProcessCombineLUTs " ) , TEXT ( " MainPS " ) , SF_Pixel ) ;
IMPLEMENT_SHADER_TYPE ( template < > , FLUTBlenderPS < 4 > , TEXT ( " PostProcessCombineLUTs " ) , TEXT ( " MainPS " ) , SF_Pixel ) ;
IMPLEMENT_SHADER_TYPE ( template < > , FLUTBlenderPS < 5 > , TEXT ( " PostProcessCombineLUTs " ) , TEXT ( " MainPS " ) , SF_Pixel ) ;
2014-06-12 07:13:34 -04:00
void SetLUTBlenderShader ( FRenderingCompositePassContext & Context , uint32 BlendCount , FTexture * Texture [ ] , float Weights [ ] , const FVolumeBounds & VolumeBounds )
2014-03-14 14:13:41 -04:00
{
check ( BlendCount > 0 ) ;
FShader * LocalPixelShader = 0 ;
FGlobalBoundShaderState * LocalBoundShaderState = 0 ;
const FSceneView & View = Context . View ;
2014-08-28 06:22:54 -04:00
const auto FeatureLevel = Context . GetFeatureLevel ( ) ;
auto ShaderMap = Context . GetShaderMap ( ) ;
2014-03-14 14:13:41 -04:00
// A macro to handle setting the filter shader for a specific number of samples.
# define CASE_COUNT(BlendCount) \
case BlendCount : \
{ \
2014-08-28 06:22:54 -04:00
TShaderMapRef < FLUTBlenderPS < BlendCount > > PixelShader ( ShaderMap ) ; \
2014-03-14 14:13:41 -04:00
static FGlobalBoundShaderState BoundShaderState ; \
LocalBoundShaderState = & BoundShaderState ; \
LocalPixelShader = * PixelShader ; \
} ; \
break ;
switch ( BlendCount )
{
// starts at 1 as we always have at least the neutral one
CASE_COUNT ( 1 ) ;
CASE_COUNT ( 2 ) ;
CASE_COUNT ( 3 ) ;
CASE_COUNT ( 4 ) ;
CASE_COUNT ( 5 ) ;
// default:
// UE_LOG(LogRenderer, Fatal,TEXT("Invalid number of samples: %u"),BlendCount);
}
# undef CASE_COUNT
check ( LocalBoundShaderState ! = NULL ) ;
2014-08-19 10:41:34 -04:00
if ( UseVolumeTextureLUT ( Context . View . GetShaderPlatform ( ) ) )
2014-03-14 14:13:41 -04:00
{
2014-08-28 06:22:54 -04:00
TShaderMapRef < FWriteToSliceVS > VertexShader ( ShaderMap ) ;
TShaderMapRef < FWriteToSliceGS > GeometryShader ( ShaderMap ) ;
2014-03-14 14:13:41 -04:00
2014-08-28 06:22:54 -04:00
SetGlobalBoundShaderState ( Context . RHICmdList , FeatureLevel , * LocalBoundShaderState , GScreenVertexDeclaration . VertexDeclarationRHI , * VertexShader , LocalPixelShader , * GeometryShader ) ;
2014-03-14 14:13:41 -04:00
2014-06-12 07:13:34 -04:00
VertexShader - > SetParameters ( Context . RHICmdList , VolumeBounds , VolumeBounds . MaxX - VolumeBounds . MinX ) ;
GeometryShader - > SetParameters ( Context . RHICmdList , VolumeBounds ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-08-28 06:22:54 -04:00
TShaderMapRef < FPostProcessVS > VertexShader ( ShaderMap ) ;
2014-03-14 14:13:41 -04:00
2014-08-28 06:22:54 -04:00
SetGlobalBoundShaderState ( Context . RHICmdList , FeatureLevel , * LocalBoundShaderState , GFilterVertexDeclaration . VertexDeclarationRHI , * VertexShader , LocalPixelShader ) ;
2014-03-14 14:13:41 -04:00
2014-06-12 07:13:34 -04:00
VertexShader - > SetParameters ( Context ) ;
2014-03-14 14:13:41 -04:00
}
# define CASE_COUNT(BlendCount) \
case BlendCount : \
{ \
2014-08-28 06:22:54 -04:00
TShaderMapRef < FLUTBlenderPS < BlendCount > > PixelShader ( ShaderMap ) ; \
2014-06-12 07:13:34 -04:00
PixelShader - > SetParameters ( Context . RHICmdList , View , Texture , Weights ) ; \
2014-03-14 14:13:41 -04:00
} ; \
break ;
switch ( BlendCount )
{
// starts at 1 as we always have at least the neutral one
CASE_COUNT ( 1 ) ;
CASE_COUNT ( 2 ) ;
CASE_COUNT ( 3 ) ;
CASE_COUNT ( 4 ) ;
CASE_COUNT ( 5 ) ;
// default:
// UE_LOG(LogRenderer, Fatal,TEXT("Invalid number of samples: %u"),BlendCount);
}
# undef CASE_COUNT
}
uint32 FRCPassPostProcessCombineLUTs : : FindIndex ( const FFinalPostProcessSettings & Settings , UTexture * Tex ) const
{
for ( uint32 i = 0 ; i < ( uint32 ) Settings . ContributingLUTs . Num ( ) ; + + i )
{
if ( Settings . ContributingLUTs [ i ] . LUTTexture = = Tex )
{
return i ;
}
}
return 0xffffffff ;
}
uint32 FRCPassPostProcessCombineLUTs : : GenerateFinalTable ( const FFinalPostProcessSettings & Settings , FTexture * OutTextures [ ] , float OutWeights [ ] , uint32 MaxCount ) const
{
// find the n strongest contributors, drop small contributors
// (inefficient implementation for many items but count should be small)
uint32 LocalCount = 1 ;
// add the neutral one (done in the shader) as it should be the first and always there
OutTextures [ 0 ] = 0 ;
{
uint32 NeutralIndex = FindIndex ( Settings , 0 ) ;
OutWeights [ 0 ] = NeutralIndex = = 0xffffffff ? 0.0f : Settings . ContributingLUTs [ NeutralIndex ] . Weight ;
}
float OutWeightsSum = OutWeights [ 0 ] ;
for ( ; LocalCount < MaxCount ; + + LocalCount )
{
uint32 BestIndex = 0xffffffff ;
// find the one with the strongest weight, add until full
for ( uint32 i = 0 ; i < ( uint32 ) Settings . ContributingLUTs . Num ( ) ; + + i )
{
bool AlreadyInArray = false ;
{
UTexture * LUTTexture = Settings . ContributingLUTs [ i ] . LUTTexture ;
FTexture * Internal = LUTTexture ? LUTTexture - > Resource : 0 ;
for ( uint32 e = 0 ; e < LocalCount ; + + e )
{
if ( Internal = = OutTextures [ e ] )
{
AlreadyInArray = true ;
break ;
}
}
}
if ( AlreadyInArray )
{
// we already have this one
continue ;
}
if ( BestIndex ! = 0xffffffff
& & Settings . ContributingLUTs [ BestIndex ] . Weight > Settings . ContributingLUTs [ i ] . Weight )
{
// we have a better ones, maybe add next time
continue ;
}
BestIndex = i ;
}
if ( BestIndex = = 0xffffffff )
{
// no more elements to process
break ;
}
float BestWeight = Settings . ContributingLUTs [ BestIndex ] . Weight ;
if ( BestWeight < 1.0f / 512.0f )
{
// drop small contributor
break ;
}
UTexture * BestLUTTexture = Settings . ContributingLUTs [ BestIndex ] . LUTTexture ;
FTexture * BestInternal = BestLUTTexture ? BestLUTTexture - > Resource : 0 ;
OutTextures [ LocalCount ] = BestInternal ;
OutWeights [ LocalCount ] = BestWeight ;
OutWeightsSum + = BestWeight ;
}
// normalize
if ( OutWeightsSum > 0.001f )
{
float InvOutWeightsSum = 1.0f / OutWeightsSum ;
for ( uint32 i = 0 ; i < LocalCount ; + + i )
{
OutWeights [ i ] * = InvOutWeightsSum ;
}
}
else
{
// neutral only is fully utilized
OutWeights [ 0 ] = 1.0f ;
LocalCount = 1 ;
}
return LocalCount ;
}
void FRCPassPostProcessCombineLUTs : : Process ( FRenderingCompositePassContext & Context )
{
2014-10-20 10:43:43 -04:00
SCOPED_DRAW_EVENT ( Context . RHICmdList , PostProcessCombineLUTs ) ;
2014-03-14 14:13:41 -04:00
FTexture * LocalTextures [ GMaxLUTBlendCount ] ;
float LocalWeights [ GMaxLUTBlendCount ] ;
const FSceneView & View = Context . View ;
const FSceneViewFamily & ViewFamily = * ( View . Family ) ;
uint32 LocalCount = 1 ;
// set defaults for no LUT
LocalTextures [ 0 ] = 0 ;
LocalWeights [ 0 ] = 1.0f ;
if ( ViewFamily . EngineShowFlags . ColorGrading )
{
LocalCount = GenerateFinalTable ( Context . View . FinalPostProcessSettings , LocalTextures , LocalWeights , GMaxLUTBlendCount ) ;
}
// for a 3D texture, the viewport is 16x16 (per slice), for a 2D texture, it's unwrapped to 256x16
2015-04-28 15:27:19 -04:00
FIntPoint DestSize ( UseVolumeTextureLUT ( ShaderPlatform ) ? GLUTSize : GLUTSize * GLUTSize , GLUTSize ) ;
2014-03-14 14:13:41 -04:00
const FSceneRenderTargetItem & DestRenderTarget = PassOutputs [ 0 ] . RequestSurface ( Context ) ;
// Set the view family's render target/viewport.
2014-06-12 07:13:34 -04:00
SetRenderTarget ( Context . RHICmdList , DestRenderTarget . TargetableTexture , FTextureRHIRef ( ) ) ;
2014-03-14 14:13:41 -04:00
Context . SetViewportAndCallRHI ( 0 , 0 , 0.0f , DestSize . X , DestSize . Y , 1.0f ) ;
// set the state
2014-06-12 07:13:34 -04:00
Context . RHICmdList . SetBlendState ( TStaticBlendState < > : : GetRHI ( ) ) ;
Context . RHICmdList . SetRasterizerState ( TStaticRasterizerState < > : : GetRHI ( ) ) ;
Context . RHICmdList . SetDepthStencilState ( TStaticDepthStencilState < false , CF_Always > : : GetRHI ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-04-28 15:27:19 -04:00
const FVolumeBounds VolumeBounds ( GLUTSize ) ;
2014-03-14 14:13:41 -04:00
2014-06-12 07:13:34 -04:00
SetLUTBlenderShader ( Context , LocalCount , LocalTextures , LocalWeights , VolumeBounds ) ;
2014-03-14 14:13:41 -04:00
2014-08-19 10:41:34 -04:00
if ( UseVolumeTextureLUT ( ShaderPlatform ) )
2014-03-14 14:13:41 -04:00
{
// use volume texture 16x16x16
2014-06-12 07:13:34 -04:00
RasterizeToVolumeTexture ( Context . RHICmdList , VolumeBounds ) ;
2014-03-14 14:13:41 -04:00
}
else
{
// use unwrapped 2d texture 256x16
2014-08-28 06:22:54 -04:00
TShaderMapRef < FPostProcessVS > VertexShader ( Context . GetShaderMap ( ) ) ;
2014-04-23 17:26:59 -04:00
2014-03-14 14:13:41 -04:00
DrawRectangle (
2014-06-12 07:13:34 -04:00
Context . RHICmdList ,
2015-04-28 15:27:19 -04:00
0 , 0 , // XY
GLUTSize * GLUTSize , GLUTSize , // SizeXY
0 , 0 , // UV
GLUTSize * GLUTSize , GLUTSize , // SizeUV
FIntPoint ( GLUTSize * GLUTSize , GLUTSize ) , // TargetSize
FIntPoint ( GLUTSize * GLUTSize , GLUTSize ) , // TextureSize
2014-04-23 17:26:59 -04:00
* VertexShader ,
2014-03-14 14:13:41 -04:00
EDRF_UseTriangleOptimization ) ;
}
2014-06-12 07:13:34 -04:00
Context . RHICmdList . CopyToResolveTarget ( DestRenderTarget . TargetableTexture , DestRenderTarget . ShaderResourceTexture , false , FResolveParams ( ) ) ;
2014-03-14 14:13:41 -04:00
}
FPooledRenderTargetDesc FRCPassPostProcessCombineLUTs : : ComputeOutputDesc ( EPassOutputId InPassOutputId ) const
{
2015-04-28 15:27:19 -04:00
FPooledRenderTargetDesc Ret = FPooledRenderTargetDesc : : Create2DDesc ( FIntPoint ( GLUTSize * GLUTSize , GLUTSize ) , PF_A2B10G10R10 , TexCreate_None , TexCreate_RenderTargetable | TexCreate_ShaderResource , false ) ;
2014-03-14 14:13:41 -04:00
2014-08-19 10:41:34 -04:00
if ( UseVolumeTextureLUT ( ShaderPlatform ) )
2014-03-14 14:13:41 -04:00
{
2015-04-28 15:27:19 -04:00
Ret . Extent = FIntPoint ( GLUTSize , GLUTSize ) ;
Ret . Depth = GLUTSize ;
2014-03-14 14:13:41 -04:00
}
Ret . DebugName = TEXT ( " CombineLUTs " ) ;
return Ret ;
2015-04-28 15:27:19 -04:00
}