You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* De-hardcode UI luminance, now driven by r.HDR.UI.Luminance * Expose hard-coded ACES tonemapper parameters: - r.HDR.Display.MinLuminanceLog10 (-4.0) defines the luminance for the darkest point in the scene, and will also compute its ACES value (through lookup_ACESmin). The same is happening with the existing CVar r.HDR.Display.MaxLuminance, through lookup_ACESmax - r.HDR.Display.MidLuminance (15.0) defines the luminance for 18% gray. It works by offseting the dakest and brightest points in the scene - r.HDR.Aces.SceneColorMultiplier (1.5) . This acts like a gain to ensure consistency between ACES (for HDR) and UE (for SDR) tonemappers. From my tests, r.HDR.Aces.SceneColorMultiplier and r.HDR.Display.MidLuminance are a bit redundant, but the former acts as a gain on the input color, whereas the latter changes the anchor points for the tonemapper. Since they don't have a linear relationship, it felt useful to keep them both. some examples: Default Values (used in initial implementation of ACES 1.3) r.HDR.Display.MinLuminanceLog10 = -4 r.HDR.Display.MidLuminance = 15 r.HDR.Aces.SceneColorMultiplier = 1.5 ACES 1.3 reference values (match reference images for r.HDR.Display.MaxLuminance=1000, 2000, 4000) r.HDR.Display.MinLuminanceLog10 = -4 r.HDR.Display.MidLuminance = 15 r.HDR.Aces.SceneColorMultiplier = 1.0 ACES 1.3 with better fit to UE SDR tonemapper (scaled to 300 nits) r.HDR.Display.MinLuminanceLog10 = -4 r.HDR.Display.MidLuminance = 54 r.HDR.Aces.SceneColorMultiplier = 1.0 #review eric.renaudhoude #jira UE-162970 #preflight 6319a664a60c539c987c1e45 [CL 21890495 by benjamin rouveyrol in ue5-main branch]
227 lines
7.4 KiB
Plaintext
227 lines
7.4 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PostProcessDeviceEncodingOnly.usf: PostProcessing device encoding only.
|
|
This replaces the tonemapper when displaying debug post process materials
|
|
used for monitor calibration.
|
|
|
|
Note: Any changes to device encoding logic must also be made
|
|
in PostProcessCombineLUTs.usf's corresponding pixel shader.
|
|
|
|
=============================================================================*/
|
|
|
|
#include "Common.ush"
|
|
#include "PostProcessCommon.ush"
|
|
#include "TonemapCommon.ush"
|
|
#include "ScreenPass.ush"
|
|
|
|
#ifndef DIM_OUTPUT_DEVICE
|
|
#define DIM_OUTPUT_DEVICE (TONEMAPPER_OUTPUT_sRGB)
|
|
#endif
|
|
|
|
SCREEN_PASS_TEXTURE_VIEWPORT(Color)
|
|
SCREEN_PASS_TEXTURE_VIEWPORT(Output)
|
|
|
|
Texture2D ColorTexture;
|
|
SamplerState ColorSampler;
|
|
|
|
float EditorNITLevel;
|
|
|
|
uint bOutputInHDR;
|
|
|
|
uint OutputDevice;
|
|
uint OutputGamut;
|
|
float OutputMaxLuminance;
|
|
|
|
float4 ACESMinMaxData;
|
|
float4 ACESMidData;
|
|
float4 ACESCoefsLow_0;
|
|
float4 ACESCoefsHigh_0;
|
|
float ACESCoefsLow_4;
|
|
float ACESCoefsHigh_4;
|
|
float ACESSceneColorMultiplier;
|
|
|
|
uint GetOutputDevice()
|
|
{
|
|
#if FEATURE_LEVEL > FEATURE_LEVEL_ES3_1
|
|
return OutputDevice;
|
|
#else
|
|
// Only sRGB output for Mobile
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
float4 SampleSceneColor(float2 SceneUV)
|
|
{
|
|
return Texture2DSample(ColorTexture, ColorSampler, SceneUV);
|
|
}
|
|
|
|
float4 DeviceEncodingOnlyCommonPS(
|
|
float2 UV,
|
|
float4 SvPosition
|
|
)
|
|
{
|
|
float4 OutColor = 0;
|
|
|
|
float2 SceneUV = UV.xy;
|
|
|
|
half4 SceneColor = SampleSceneColor(SceneUV);
|
|
|
|
const float3x3 AP1_2_Output = OuputGamutMappingMatrix( OutputGamut );
|
|
|
|
// Apply "gamma" curve adjustment.
|
|
float3 FilmColor = pow(max(0, SceneColor.rgb), InverseGamma.y);
|
|
|
|
// Note: Any changes to device encoding logic below must also be made
|
|
// in PostProcessCombineLUTs.usf's corresponding pixel shader.
|
|
half3 OutDeviceColor = 0;
|
|
BRANCH
|
|
|
|
// sRGB, user specified gamut
|
|
if( GetOutputDevice() == TONEMAPPER_OUTPUT_sRGB)
|
|
{
|
|
// Convert from sRGB to specified output gamut
|
|
// float3 OutputGamutColor = mul( AP1_2_Output, mul( sRGB_2_AP1, FilmColor ) );
|
|
|
|
// FIXME: Workaround for UE-29935, pushing all colors with a 0 component to black output
|
|
// Default parameters seem to cancel out (sRGB->XYZ->AP1->XYZ->sRGB), so should be okay for a temp fix
|
|
float3 OutputGamutColor = WorkingColorSpace.bIsSRGB ? FilmColor : mul( AP1_2_Output, mul( (float3x3)WorkingColorSpace.ToAP1, FilmColor ) );
|
|
|
|
// Apply conversion to sRGB (this must be an exact sRGB conversion else darks are bad).
|
|
OutDeviceColor = LinearToSrgb( OutputGamutColor );
|
|
}
|
|
|
|
// Rec 709, user specified gamut
|
|
else if( GetOutputDevice() == TONEMAPPER_OUTPUT_Rec709)
|
|
{
|
|
// Convert from sRGB to specified output gamut
|
|
float3 OutputGamutColor = mul( AP1_2_Output, mul( (float3x3)WorkingColorSpace.ToAP1, FilmColor ) );
|
|
|
|
// Didn't profile yet if the branching version would be faster (different linear segment).
|
|
OutDeviceColor = LinearTo709Branchless( OutputGamutColor );
|
|
}
|
|
|
|
// ACES 1000nit transform with PQ/2084 encoding, user specified gamut
|
|
else if( GetOutputDevice() == TONEMAPPER_OUTPUT_ACES1000nitST2084 )
|
|
{
|
|
// 1000 nit ODT
|
|
FACESTonemapParams AcesParams = ComputeACESTonemapParams(ACESMinMaxData, ACESMidData, ACESCoefsLow_0, ACESCoefsHigh_0, ACESCoefsLow_4, ACESCoefsHigh_4, ACESSceneColorMultiplier);
|
|
float3 ODTColor = ACESOutputTransforms1000( FilmColor, (float3x3)WorkingColorSpace.ToAP0, AcesParams);
|
|
|
|
// Convert from AP1 to specified output gamut
|
|
ODTColor = mul( AP1_2_Output, ODTColor );
|
|
|
|
// Apply conversion to ST-2084 (Dolby PQ)
|
|
OutDeviceColor = LinearToST2084( ODTColor );
|
|
}
|
|
|
|
// ACES 2000nit transform with PQ/2084 encoding, user specified gamut
|
|
else if( GetOutputDevice() == TONEMAPPER_OUTPUT_ACES2000nitST2084 )
|
|
{
|
|
FACESTonemapParams AcesParams = ComputeACESTonemapParams(ACESMinMaxData, ACESMidData, ACESCoefsLow_0, ACESCoefsHigh_0, ACESCoefsLow_4, ACESCoefsHigh_4, ACESSceneColorMultiplier);
|
|
|
|
// 2000 nit ODT
|
|
float3 ODTColor = ACESOutputTransforms2000( FilmColor, (float3x3)WorkingColorSpace.ToAP0, AcesParams);
|
|
|
|
// Convert from AP1 to specified output gamut
|
|
ODTColor = mul( AP1_2_Output, ODTColor );
|
|
|
|
// Apply conversion to ST-2084 (Dolby PQ)
|
|
OutDeviceColor = LinearToST2084( ODTColor );
|
|
}
|
|
|
|
// ACES 1000nit transform to linear ScRGB
|
|
else if(GetOutputDevice() == TONEMAPPER_OUTPUT_ACES1000nitScRGB)
|
|
{
|
|
FACESTonemapParams AcesParams = ComputeACESTonemapParams(ACESMinMaxData, ACESMidData, ACESCoefsLow_0, ACESCoefsHigh_0, ACESCoefsLow_4, ACESCoefsHigh_4, ACESSceneColorMultiplier);
|
|
|
|
// 1000 nit ODT
|
|
float3 ODTColor = ACESOutputTransforms1000( FilmColor, (float3x3)WorkingColorSpace.ToAP0, AcesParams);
|
|
|
|
// Apply conversion to ScRGB
|
|
OutDeviceColor = ST2084ToScRGB( LinearToST2084( ODTColor ), TONEMAPPER_OUTPUT_ACES1000nitScRGB, OutputMaxLuminance );
|
|
}
|
|
|
|
// ACES 2000nit transform to linear ScRGB
|
|
else if(GetOutputDevice() == TONEMAPPER_OUTPUT_ACES2000nitScRGB)
|
|
{
|
|
FACESTonemapParams AcesParams = ComputeACESTonemapParams(ACESMinMaxData, ACESMidData, ACESCoefsLow_0, ACESCoefsHigh_0, ACESCoefsLow_4, ACESCoefsHigh_4, ACESSceneColorMultiplier);
|
|
|
|
// 2000 nit ODT
|
|
float3 ODTColor = ACESOutputTransforms2000( FilmColor, (float3x3)WorkingColorSpace.ToAP0, AcesParams);
|
|
|
|
// Apply conversion to ScRGB
|
|
OutDeviceColor = ST2084ToScRGB( LinearToST2084( ODTColor ), TONEMAPPER_OUTPUT_ACES2000nitScRGB, OutputMaxLuminance );
|
|
}
|
|
|
|
else if( GetOutputDevice() == TONEMAPPER_OUTPUT_LinearEXR)
|
|
{
|
|
float3 OutputGamutColor = mul( AP1_2_Output, mul( (float3x3)WorkingColorSpace.ToAP1, FilmColor ) );
|
|
OutDeviceColor = LinearToST2084( OutputGamutColor );
|
|
}
|
|
// Linear HDR, including all color correction, but no tone curve
|
|
else if( GetOutputDevice() == TONEMAPPER_OUTPUT_NoToneCurve)
|
|
{
|
|
OutDeviceColor = FilmColor;
|
|
}
|
|
// "Linear" including all color correction and the tone curve, but no device gamma
|
|
else if (GetOutputDevice() == TONEMAPPER_OUTPUT_WithToneCurve)
|
|
{
|
|
float3 OutputGamutColor = mul( AP1_2_Output, mul( (float3x3)WorkingColorSpace.ToAP1, SceneColor.rgb ) );
|
|
|
|
OutDeviceColor = OutputGamutColor;
|
|
}
|
|
|
|
// OutputDevice == TONEMAPPER_OUTPUT_ExplicitGammaMapping
|
|
// Gamma 2.2, user specified gamut
|
|
else
|
|
{
|
|
// Convert from sRGB to specified output gamut
|
|
float3 OutputGamutColor = mul( AP1_2_Output, mul( (float3x3)WorkingColorSpace.ToAP1, FilmColor ) );
|
|
|
|
// This is different than the prior "gamma" curve adjustment (but reusing the variable).
|
|
// For displays set to a gamma colorspace.
|
|
// Note, MacOSX native output is raw gamma 2.2 not sRGB!
|
|
OutDeviceColor = pow( OutputGamutColor, InverseGamma.z );
|
|
}
|
|
|
|
OutColor.rgb = OutDeviceColor;
|
|
OutColor.a = 1;
|
|
|
|
return OutColor;
|
|
}
|
|
|
|
// pixel shader entry point
|
|
void MainPS(
|
|
in noperspective float2 UV : TEXCOORD0,
|
|
float4 SvPosition : SV_POSITION, // after all interpolators
|
|
out float4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
OutColor = DeviceEncodingOnlyCommonPS(UV, SvPosition);
|
|
}
|
|
|
|
#if COMPUTESHADER
|
|
RWTexture2D<float4> RWOutputTexture;
|
|
|
|
[numthreads(THREADGROUP_SIZEX, THREADGROUP_SIZEY, 1)]
|
|
void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
float4 SvPosition = float4((float2)DispatchThreadId + Output_ViewportMin + 0.5f, 0.0f, 1.0f);
|
|
float2 UV = SvPosition.xy * Output_ExtentInverse;
|
|
float4 InScreenPos = float4(UV*2-1,0,1);
|
|
|
|
if (IsComputeUVOutOfBounds(UV))
|
|
{
|
|
return;
|
|
}
|
|
|
|
float4 OutColor = DeviceEncodingOnlyCommonPS(UV, SvPosition);
|
|
|
|
uint2 PixelPos = DispatchThreadId + Output_ViewportMin;
|
|
RWOutputTexture[PixelPos] = OutColor;
|
|
}
|
|
#endif
|
|
|
|
|