Files
UnrealEngine/Engine/Shaders/Private/PostProcessVisualizeLocalExposure.usf
2025-05-18 13:04:45 +08:00

180 lines
6.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Common.ush"
#include "ScreenPass.ush"
#include "PostProcessCommon.ush"
#include "PostProcessHistogramCommon.ush"
#include "DeferredShadingCommon.ush"
#include "TonemapCommon.ush"
StructuredBuffer<float4> EyeAdaptationBuffer;
Texture2D HDRSceneColorTexture;
Texture2D SceneColorTexture;
#if !EXPOSURE_FUSION
Texture3D LumBilateralGrid;
Texture2D BlurredLogLum;
#else
FScreenTransform ColorToExposureFusion;
SCREEN_PASS_TEXTURE_VIEWPORT(ExposureFusion)
Texture2D ExposureFusionTexture;
Texture2D ExposuresTexture;
Texture2D WeightsTexture;
#endif
SamplerState BilinearClampSampler;
uint DebugMode;
#define VISUALIZE_LOCAL_EXPOSURE_MODE_DEFAULT (1)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_THRESHOLDS (2)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_BASE_LUMINANCE (3)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_DETAIL_LUMINANCE (4)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_VALID_LOOKUP (5)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_BASE (6)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_SHADOWS (7)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_HIGHLIGHTS (8)
#define VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_WEIGHTS (9)
SCREEN_PASS_TEXTURE_VIEWPORT(Input)
SCREEN_PASS_TEXTURE_VIEWPORT(Output)
float DiagonalStripesPattern(float2 ScreenPos, float Thickness)
{
float V = frac((ScreenPos.x + ScreenPos.y) / Thickness);
return step(0.5f, V);
}
float4 MainPS(noperspective float4 UVAndScreenPos : TEXCOORD0, float4 SvPosition : SV_POSITION) : SV_Target0
{
float2 UV = UVAndScreenPos.xy;
float2 ViewportUV = (int2(SvPosition.xy) - Output_ViewportMin) * Output_ViewportSizeInverse;
float2 ExposureScaleMiddleGrey = EyeAdaptationBuffer[0].xw;
float4 HDRSceneColor = Texture2DSample(HDRSceneColorTexture, BilinearClampSampler, UV) * View.OneOverPreExposure;
float4 SceneColor = Texture2DSample(SceneColorTexture, BilinearClampSampler, UV);
float LuminanceVal = CalculateEyeAdaptationLuminance(HDRSceneColor.rgb);
float LogLuminance = log2(LuminanceVal);
float MiddleGreyLumValue = log2(0.18 * ExposureScaleMiddleGrey.y * LocalExposure_MiddleGreyExposureCompensation);
#if !EXPOSURE_FUSION
float BaseLogLum = CalculateBaseLogLuminance(LogLuminance, LocalExposure_BlurredLuminanceBlend, ExposureScaleMiddleGrey.x, ViewportUV, LumBilateralGrid, BlurredLogLum, BilinearClampSampler, BilinearClampSampler);
float LocalExposure = CalculateLocalExposure(LogLuminance + log2(ExposureScaleMiddleGrey.x), BaseLogLum, MiddleGreyLumValue, LocalExposure_HighlightContrastScale, LocalExposure_ShadowContrastScale, LocalExposure_DetailStrength);
float DetailLogLum = (LogLuminance + log2(ExposureScaleMiddleGrey.x)) - BaseLogLum;
#else
float BaseLogLum = LogLuminance + log2(ExposureScaleMiddleGrey.x);
float2 ExposureFusionUV = ApplyScreenTransform(UV.xy, ColorToExposureFusion);
ExposureFusionUV = clamp(ExposureFusionUV, ExposureFusion_UVViewportBilinearMin, ExposureFusion_UVViewportBilinearMax);
float4 Exposures = Texture2DSample(ExposuresTexture, BilinearClampSampler, ExposureFusionUV);
float4 Weights = Texture2DSample(WeightsTexture, BilinearClampSampler, ExposureFusionUV);
const float LuminanceVal2 = CalculateEyeAdaptationLuminance(HDRSceneColor.rgb * ExposureScaleMiddleGrey.x);
float FusionVal = Texture2DSample(ExposureFusionTexture, BilinearClampSampler, ExposureFusionUV).x;
float LocalExposure = CalculateFusionLocalExposure(LuminanceVal2, FusionVal);
#endif
float BaseCentered = (BaseLogLum - MiddleGreyLumValue);
float3 OutValue = 0;
if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_DEFAULT)
{
OutValue = saturate(abs(log2(LocalExposure) / 2)) * lerp(float3(1.0f, 0.0f, 0.0f), float3(0.0f, 1.0f, 0.0f), step(LocalExposure, 1));
}
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_THRESHOLDS)
{
OutValue = SceneColor.rgb;
if (BaseCentered > 0)
{
if (BaseCentered - LocalExposure_HighlightThreshold > 0)
{
OutValue = lerp(OutValue, float3(0,1,0), DiagonalStripesPattern(SvPosition.xy, 32.0f));
}
}
else
{
if (BaseCentered + LocalExposure_ShadowThreshold < 0)
{
OutValue = lerp(OutValue, float3(1,0,0), DiagonalStripesPattern(SvPosition.xy, 32.0f));
}
}
}
#if !EXPOSURE_FUSION
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_BASE_LUMINANCE)
{
float ContrastScale = BaseCentered > 0 ? LocalExposure_HighlightContrastScale : LocalExposure_ShadowContrastScale;
// Apply threshold
float ThresholdOffset;
{
if (BaseCentered > 0)
{
ThresholdOffset = BaseCentered - max(0.0f, BaseCentered - LocalExposure_HighlightThreshold);
}
else
{
ThresholdOffset = BaseCentered - min(0.0f, BaseCentered + LocalExposure_ShadowThreshold);
}
BaseCentered -= ThresholdOffset;
}
OutValue = exp2(MiddleGreyLumValue + ThresholdOffset + BaseCentered * ContrastScale);
}
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_DETAIL_LUMINANCE)
{
OutValue = exp2(DetailLogLum * LocalExposure_DetailStrength);
}
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_VALID_LOOKUP)
{
OutValue = SceneColor.rgb;
float3 BilateralGridUVW;
BilateralGridUVW.xy = ViewportUV * LocalExposure_BilateralGridUVScale;
BilateralGridUVW.z = (ComputeHistogramPositionFromLogLuminance(LogLuminance) * (BILATERAL_GRID_DEPTH - 1) + 0.5f) / BILATERAL_GRID_DEPTH;
float2 BilateralGridLum = Texture3DSample(LumBilateralGrid, BilinearClampSampler, BilateralGridUVW).xy;
if (BilateralGridLum.y < 0.001)
{
// bilateral grid doesn't have valid data
OutValue = float3(1,0,0);
}
else
{
OutValue = lerp(OutValue, float3(0,1,0), 0.5f);
}
}
#else
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_BASE)
{
OutValue = Exposures.r;
}
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_HIGHLIGHTS)
{
OutValue = Exposures.g;
}
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_SHADOWS)
{
OutValue = Exposures.b;
}
else if (DebugMode == VISUALIZE_LOCAL_EXPOSURE_MODE_FUSION_WEIGHTS)
{
// swap rb channels so colors match other visualizations
// red = shadows
// green = highlights
float T = Weights.r;
Weights.r = Weights.b;
Weights.b = T;
OutValue = Weights.rgb;
}
#endif
return float4(OutValue, 1.0f);
}