Files
UnrealEngineUWP/Engine/Shaders/PostProcessHistogramCommon.usf
Ben Marsh 20bf0eb6a1 Updating copyright notices to 2017 (copying from //Tasks/UE4/Dev-Copyright-2017).
#rb none
#lockdown Nick.Penwarden

[CL 3226823 by Ben Marsh in Main branch]
2016-12-08 08:52:44 -05:00

145 lines
4.7 KiB
Plaintext

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PostProcessHistogramCommon.usf: PostProcessing histogram shared functions and structures.
=============================================================================*/
// [0] .x:ExposureLowPercent/100, .y:EyeAdaptationHighPercent/100, .z:EyeAdaptationMin, .w:EyeAdaptationMax
// [1] .x:exp2(ExposureOffset), .y:DeltaWorldTime, .zw: EyeAdaptionSpeedUp/Down
// [2] .x:Histogram multiply, .y:Histogram add, .z:HistogramMinIntensity w:unused
float4 EyeAdaptationParams[3];
// inverse of ComputeLuminanceFromHistogramPosition
// is executed more often than ComputeLuminanceFromHistogramPosition()
// @param Luminance
// @return HistogramPosition 0..1
float ComputeHistogramPositionFromLuminance(float Luminance)
{
return log2(Luminance) * EyeAdaptationParams[2].x + EyeAdaptationParams[2].y;
}
// inverse of ComputeHistogramPositionFromLuminance()
// is not as often executed as ComputeHistogramPositionFromLuminance()
// @param HistogramPosition 0..1
// @return Lumiance
float ComputeLuminanceFromHistogramPosition(float HistogramPosition)
{
return exp2( (HistogramPosition - EyeAdaptationParams[2].y) / EyeAdaptationParams[2].x );
}
#define HISTOGRAM_SIZE 64
#define HISTOGRAM_TEXEL_SIZE (HISTOGRAM_SIZE / 4)
float4 ComputeARGBStripeMaskInt(uint x)
{
#if ES2_PROFILE
// Integer modulo/remainder is not an allowed operation on ES 2
// todo: move function to central spot, here we assume unsigned
uint Temp = x - (x / 4) * 4;
return float4(
Temp == 0,
Temp == 1,
Temp == 2,
Temp == 3);
#else
return float4(
(x % 4) == 0,
(x % 4) == 1,
(x % 4) == 2,
(x % 4) == 3);
#endif
}
float GetHistogramBucket(Texture2D HistogramTexture, uint BucketIndex)
{
uint Texel = BucketIndex / 4;
float4 HistogramColor = HistogramTexture.Load(int3(Texel, 0, 0));
// WAR for a GLSL shader compiler bug in the driver
#if 0
float UnweightedValue = dot(HistogramColor, ComputeARGBStripeMaskInt(BucketIndex));
#else
#if ES2_PROFILE
// Integer modulo/remainder is not an allowed operation on ES 2
// todo: move function to central spot, here we assume unsigned
uint channel = BucketIndex - (BucketIndex / 4) * 4;
#else
uint channel = BucketIndex % 4;
#endif
float UnweightedValue = HistogramColor.r;
UnweightedValue = (channel == 1) ? HistogramColor.g : UnweightedValue;
UnweightedValue = (channel == 2) ? HistogramColor.b : UnweightedValue;
UnweightedValue = (channel == 3) ? HistogramColor.a : UnweightedValue;
#endif
// because of the logarithmic scale we need to weight the buckets ?
// return UnweightedValue * pow(2, BucketIndex);
// return UnweightedValue * pow(2, BucketIndex / HISTOGRAM_SIZE * (2 * HDRLogRadius));
return UnweightedValue;
}
float ComputeHistogramSum(Texture2D HistogramTexture)
{
float Sum = 0;
for(uint i = 0; i < HISTOGRAM_SIZE; ++i)
{
Sum += GetHistogramBucket(HistogramTexture, i);
}
return Sum;
}
// @param MinFractionSum e.g. ComputeHistogramSum() * 0.5f for 50% percentil
// @param MaxFractionSum e.g. ComputeHistogramSum() * 0.9f for 90% percentil
float ComputeAverageLuminaneWithoutOutlier(Texture2D HistogramTexture, float MinFractionSum, float MaxFractionSum)
{
float2 SumWithoutOutliers = 0;
UNROLL for(uint i = 0; i < HISTOGRAM_SIZE; ++i)
{
float LocalValue = GetHistogramBucket(HistogramTexture, i);
// remove outlier at lower end
float Sub = min(LocalValue, MinFractionSum);
LocalValue = LocalValue - Sub;
MinFractionSum -= Sub;
MaxFractionSum -= Sub;
// remove outlier at upper end
LocalValue = min(LocalValue, MaxFractionSum);
MaxFractionSum -= LocalValue;
float LuminanceAtBucket = ComputeLuminanceFromHistogramPosition(i / (float)HISTOGRAM_SIZE);
SumWithoutOutliers += float2(LuminanceAtBucket, 1) * LocalValue;
}
return SumWithoutOutliers.x / max(0.0001f, SumWithoutOutliers.y);
}
// used by bloom and tonemapper VS
// requires EyeAdaptationParams to be set
float ComputeEyeAdaptationExposure(Texture2D HistogramTexture)
{
float HistogramSum = ComputeHistogramSum(HistogramTexture);
float UnclampedAdaptedLuminance = ComputeAverageLuminaneWithoutOutlier(HistogramTexture, HistogramSum * EyeAdaptationParams[0].x, HistogramSum * EyeAdaptationParams[0].y);
float ClampedAdaptedLuminance = clamp(UnclampedAdaptedLuminance, EyeAdaptationParams[0].z, EyeAdaptationParams[0].w);
return ClampedAdaptedLuminance;
}
// Computation of triangle function on normalized space
// used in Basic EyeAdaptation in weighting the center of the screen
// @return range of 0..1 with 1 nx = 0.5
// @param nx in 0..1
// @param slope assumed possitive
float AdaptationWeight(float nx, float slope)
{
return max(1.f - 2. * slope * abs(nx - 0.5f), 0.0f);
}