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

99 lines
4.0 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================================
ReferencePathTracinPixelShader.ush: Reference path tracing compositing pixel shader for progressive update.
===============================================================================================*/
#include "../Common.ush"
#include "../ColorMap.ush"
#include "PathTracingAdaptiveUtils.ush"
uint Iteration;
uint MaxSamples;
int ProgressDisplayEnabled;
Texture2D<float4> RadianceTexture;
Texture2D<float> DepthTexture;
float PreExposure; // Taken from the view, but adjusted by the base exposure already applied to the Radiance texture
int AdaptiveSamplingVisualize;
void CompositeMain(
in noperspective float4 UVAndScreenPos : TEXCOORD0,
out float4 OutColor : SV_Target0,
out float OutDepth : SV_DEPTH
)
{
float2 UV = UVAndScreenPos.xy;
float2 BufferSize = View.BufferSizeAndInvSize.xy;
int3 TexCoord = int3(UV * BufferSize - View.ViewRectMin.xy, 0);
float4 Radiance = RadianceTexture.Load(TexCoord);
Radiance = select(IsFinite(Radiance), Radiance, MaxHalfFloat); // if any component overflowed half precision, clamp it now
// NOTE: UE has the convention of using 1.0 - Alpha
// We must saturate the result because the path tracer's alpha is stochastic in the presence of volumetrics
// It is important that the clamp happens _after_ averaging, otherwise this can bias the estimate
OutColor = float4(Radiance.rgb * PreExposure, saturate(1.0 - Radiance.a));
if (AdaptiveSamplingVisualize == 1)
{
// Visualize which pixels are still being worked and color them according to how many more samples we think they need
float2 VarianceUV = float2(TexCoord.xy + 0.5) * View.BufferSizeAndInvSize.zw;
float SampleScaleFactor = GetAdaptiveSampleFactor(TexCoord.xy, View.PreExposure);
if (SampleScaleFactor > 1.0)
{
float4 Variance = VarianceTexture.Load(TexCoord);
float Ramp = Variance.z * SampleScaleFactor / MaxSamples;
OutColor.xyz = ColorMapTurbo(Ramp);
}
}
if (AdaptiveSamplingVisualize == 2)
{
// Visualize sample count relative to maximum
float4 Variance = VarianceTexture.Load(TexCoord);
float Ramp = Variance.z / min(Iteration + 1, MaxSamples);
OutColor.xyz = ColorMapTurbo(Ramp);
}
if (AdaptiveSamplingVisualize >= 3 && AdaptiveSamplingVisualize < 3 + int(VarianceTextureDims.z))
{
//float4 Variance = VarianceTexture.Load(TexCoord);
float2 VarianceUV = float2(TexCoord.xy + 0.5) / float2(VarianceTextureDims.xy);
int Mip = AdaptiveSamplingVisualize - 3;
float4 Variance = SampleVarianceTexture(VarianceUV, Mip);
float NumSamples = Variance.z;
float OutVariance = Variance.y - Variance.x * Variance.x;
float Lum = Variance.x;
float StdErr = sqrt(OutVariance / NumSamples);
float RelErr = PerceptualError(Lum, StdErr, View.PreExposure);
OutColor.xyz = RelErr;
}
if (ProgressDisplayEnabled && (Iteration + 1) < MaxSamples)
{
// Draw a progress meter for how far along we are to the max number of passes
float Aspect = View.BufferSizeAndInvSize.y * View.BufferSizeAndInvSize.z;
float Size = 50.0 * View.BufferSizeAndInvSize.z;
float2 P = float2(UV.x, UV.y * Aspect);
float2 RectMin = View.ViewRectMin.xy;
float2 RectMax = View.ViewRectMin.xy + View.ViewSizeAndInvSize.xy;
// center progress in middle-bottom of the frame
float2 Center = float2(lerp(RectMin.x, RectMax.x, 0.5), RectMax.y) * View.BufferSizeAndInvSize.zz - float2(0, Size * 0.75);
P -= Center;
float Fraction = saturate(float(Iteration + 1) / float(MaxSamples));
// simple linear progress bar
float2 ProgressSize = float2(2.0 * Size, 0.15 * Size);
if (all(abs(P) < ProgressSize))
{
P += ProgressSize;
P /= ProgressSize * 2;
float Blend = smoothstep(Fraction - fwidth(P.x), Fraction + fwidth(P.x), P.x);
// Grey/Red blend
float3 ProgressBarColor = lerp(float3(1.0, 0.1, 0.1), float3(0.5, 0.5, 0.5), Blend);
OutColor.xyz = lerp(OutColor.xyz, ProgressBarColor, 0.75);
}
}
OutDepth = DepthTexture.Load(TexCoord);
}