Files
UnrealEngineUWP/Engine/Shaders/TonemapCommon.usf
Peter Sauerbrei b0f99c10f7 fix shader compile failure when compiling for Metal
#ios
#codereview rolando.caloca

[CL 2530795 by Peter Sauerbrei in Main branch]
2015-04-29 16:52:49 -04:00

222 lines
7.0 KiB
Plaintext

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
TonemapCommon.usf: PostProcessing tone mapping common
=============================================================================*/
// #todo-rco: Fix in the cross-compiler
#if COMPILER_GLSL || COMPILER_GLSL_ES2 || METAL_PROFILE
#define log10(x) log(x) / log(10.0)
#endif
#include "ACES.usf"
// usually 1/2.2, the .y is used for inverse gamma when "gamma only" mode is not used
half3 InverseGamma;
// Film tonal and color control.
half4 ColorMatrixR_ColorCurveCd1;
half4 ColorMatrixG_ColorCurveCd3Cm3;
half4 ColorMatrixB_ColorCurveCm2;
half4 ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3;
half4 ColorCurve_Ch1_Ch2;
half4 ColorShadow_Luma;
half4 ColorShadow_Tint1;
half4 ColorShadow_Tint2;
half3 FilmPostProcess(half3 LinearColor)
{
// Color and exposure control.
half3 MatrixColor;
#if USE_COLOR_MATRIX == 1
// Apply color matrix (channel mixer, exposure, saturation).
MatrixColor.r = dot(LinearColor, ColorMatrixR_ColorCurveCd1.rgb);
MatrixColor.g = dot(LinearColor, ColorMatrixG_ColorCurveCd3Cm3.rgb);
MatrixColor.b = dot(LinearColor, ColorMatrixB_ColorCurveCm2.rgb);
#if USE_SHADOW_TINT == 1
MatrixColor *= ColorShadow_Tint1.rgb + ColorShadow_Tint2.rgb * rcp(dot(LinearColor, ColorShadow_Luma.rgb) + 1.0);
#endif
// Required to insure saturation doesn't create negative colors!
MatrixColor = max(half3(0.0, 0.0, 0.0), MatrixColor);
#else
// Less expensive route when not using saturation and channel mixer.
#if USE_SHADOW_TINT == 1
MatrixColor = LinearColor * (ColorShadow_Tint1.rgb + ColorShadow_Tint2.rgb * rcp(dot(LinearColor, ColorShadow_Luma.rgb) + 1.0));
#else
MatrixColor = LinearColor * ColorMatrixB_ColorCurveCm2.rgb;
#endif
#endif
// Apply color curve (includes tonemapping).
#if USE_CONTRAST == 1
// Full path.
half3 MatrixColorD = max(0, ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx - MatrixColor);
half3 MatrixColorH = max(MatrixColor, ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz);
half3 MatrixColorM = clamp(MatrixColor, ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx, ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz);
half3 CurveColor =
// Highlights
(MatrixColorH*ColorCurve_Ch1_Ch2.xxx + ColorCurve_Ch1_Ch2.yyy) * rcp(MatrixColorH + ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.www) +
// Midtones
((MatrixColorM*ColorMatrixB_ColorCurveCm2.aaa +
// Darks
((MatrixColorD*ColorMatrixR_ColorCurveCd1.aaa) * rcp(MatrixColorD + ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.yyy) + ColorMatrixG_ColorCurveCd3Cm3.aaa)));
#else
// This is for mobile, it assumes color is not negative.
// Fast path when contrast=1, can remove the dark part of the curve.
half3 MatrixColorH = max(MatrixColor, ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz);
half3 MatrixColorM = min(MatrixColor, ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz);
half3 CurveColor = (MatrixColorH*ColorCurve_Ch1_Ch2.xxx + ColorCurve_Ch1_Ch2.yyy) * rcp(MatrixColorH + ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.www) + MatrixColorM;
#endif
return CurveColor;
}
half3 TonemapAndGammaCorrect(half3 LinearColor)
{
// Clamp input to be positive
// This displays negative colors as black
LinearColor = max(LinearColor, 0);
half3 GammaColor = pow(LinearColor, InverseGamma.x);
// in all cases it's good to clamp into the 0..1 range (e.g for LUT color grading)
GammaColor = saturate(GammaColor);
return GammaColor;
}
/*
============================================
// Uncharted settings
Slope = 0.63;
Toe = 0.55;
Shoulder = 0.47;
BlackClip= 0;
WhiteClip = 0.01;
// HP settings
Slope = 0.65;
Toe = 0.63;
Shoulder = 0.45;
BlackClip = 0;
WhiteClip = 0;
// Weta settings
Slope = 0.6;
Toe = 0.72;
Shoulder = 0.55;
BlackClip = 0;
WhiteClip = 0.02;
// Legacy settings
Slope = 0.98;
Toe = 0.3;
Shoulder = 0.22;
BlackClip = 0;
WhiteClip = 0.025;
// ACES settings
Slope = 0.88;
Toe = 0.55;
Shoulder = 0.26;
BlackClip = 0;
WhiteClip = 0.04;
===========================================
*/
float FilmSlope;
float FilmToe;
float FilmShoulder;
float FilmBlackClip;
float FilmWhiteClip;
half3 FilmToneMap( half3 LinearColor )
{
const float3x3 sRGB_2_AP0 = mul( XYZ_2_AP0_MAT, mul( D65_2_D60_CAT, sRGB_2_XYZ_MAT ) );
const float3x3 sRGB_2_AP1 = mul( XYZ_2_AP1_MAT, mul( D65_2_D60_CAT, sRGB_2_XYZ_MAT ) );
const float3x3 AP1_2_sRGB = mul( XYZ_2_sRGB_MAT, mul( D60_2_D65_CAT, AP1_2_XYZ_MAT ) );
#if 1
float3 ACESColor = mul( sRGB_2_AP0, LinearColor );
// --- Red modifier --- //
const float RRT_RED_SCALE = 0.82;
const float RRT_RED_PIVOT = 0.03;
const float RRT_RED_HUE = 0;
const float RRT_RED_WIDTH = 135;
float saturation = rgb_2_saturation( ACESColor );
float hue = rgb_2_hue( ACESColor );
float centeredHue = center_hue( hue, RRT_RED_HUE );
float hueWeight = Square( smoothstep( 0, 1, 1 - abs( 2 * centeredHue / RRT_RED_WIDTH ) ) );
ACESColor.r += hueWeight * saturation * (RRT_RED_PIVOT - ACESColor.r) * (1. - RRT_RED_SCALE);
// Use ACEScg primaries as working space
float3 WorkingColor = mul( AP0_2_AP1_MAT, ACESColor );
#else
// Use ACEScg primaries as working space
float3 WorkingColor = mul( sRGB_2_AP1, LinearColor );
#endif
WorkingColor = max( 0, WorkingColor );
// Pre desaturate
WorkingColor = lerp( dot( WorkingColor, AP1_RGB2Y ), WorkingColor, 0.96 );
const half ToeScale = 1 + FilmBlackClip - FilmToe;
const half ShoulderScale = 1 + FilmWhiteClip - FilmShoulder;
const float InMatch = 0.18;
const float OutMatch = 0.18;
float ToeMatch;
if( FilmToe > 0.8 )
{
// 0.18 will be on straight segment
ToeMatch = ( 1 - FilmToe - OutMatch ) / FilmSlope + log10( InMatch );
}
else
{
// 0.18 will be on toe segment
// Solve for ToeMatch such that input of InMatch gives output of OutMatch.
const float bt = ( OutMatch + FilmBlackClip ) / ToeScale - 1;
ToeMatch = log10( InMatch ) - 0.5 * log( (1+bt)/(1-bt) ) * (ToeScale / FilmSlope);
}
float StraightMatch = ( 1 - FilmToe ) / FilmSlope - ToeMatch;
float ShoulderMatch = FilmShoulder / FilmSlope - StraightMatch;
half3 LogColor = log10( WorkingColor );
half3 StraightColor = FilmSlope * ( LogColor + StraightMatch );
half3 ToeColor = ( -FilmBlackClip ) + (2 * ToeScale) / ( 1 + exp( (-2 * FilmSlope / ToeScale) * ( LogColor - ToeMatch ) ) );
half3 ShoulderColor = ( 1 + FilmWhiteClip ) - (2 * ShoulderScale) / ( 1 + exp( ( 2 * FilmSlope / ShoulderScale) * ( LogColor - ShoulderMatch ) ) );
ToeColor = LogColor < ToeMatch ? ToeColor : StraightColor;
ShoulderColor = LogColor > ShoulderMatch ? ShoulderColor : StraightColor;
half3 t = saturate( ( LogColor - ToeMatch ) / ( ShoulderMatch - ToeMatch ) );
t = ShoulderMatch < ToeMatch ? 1 - t : t;
t = (3-2*t)*t*t;
half3 ToneColor = lerp( ToeColor, ShoulderColor, t );
// Post desaturate
ToneColor = lerp( dot( ToneColor, AP1_RGB2Y ), ToneColor, 0.93 );
ToneColor = mul( AP1_2_sRGB, ToneColor );
//return saturate( ToneColor );
return max( 0, ToneColor );
}
float3 ACES( float3 LinearColor )
{
const float3x3 sRGB_2_AP0 = mul( XYZ_2_AP0_MAT, mul( D65_2_D60_CAT, sRGB_2_XYZ_MAT ) );
float3 aces = mul( sRGB_2_AP0, LinearColor * 1.5 );
float3 oces = RRT( aces );
return ODT( oces );
}