You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
3.6 KiB
Plaintext
90 lines
3.6 KiB
Plaintext
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <scenesrg.srgi>
|
|
#include <viewsrg.srgi>
|
|
|
|
#include <Atom/RPI/Math.azsli>
|
|
#include "EyeAdaptationUtil.azsli"
|
|
|
|
ShaderResourceGroup PassSrg : SRG_PerPass
|
|
{
|
|
// This is a mip chain containing the scene luminance info
|
|
// x = min luminance
|
|
// y = average luminance
|
|
// z = max luminance
|
|
Texture2D<float4> m_sceneLuminance;
|
|
|
|
Sampler LinearSampler
|
|
{
|
|
MinFilter = Linear;
|
|
MagFilter = Linear;
|
|
MipFilter = Linear;
|
|
AddressU = Clamp;
|
|
AddressV = Clamp;
|
|
AddressW = Clamp;
|
|
};
|
|
|
|
// Contains the eye-adaptation feedback settings. This buffer will be updated in this pass.
|
|
RWStructuredBuffer<EyeAdaptation> m_eyeAdaptationData;
|
|
}
|
|
|
|
[numthreads(1, 1, 1)]
|
|
void MainCS(uint3 dispatch_id : SV_DispatchThreadID)
|
|
{
|
|
// Determine the goal exposure value in logarithmic(perceptual) space.
|
|
float goalExposureLog2 = 0.0; // default goal is no adjustment
|
|
|
|
if (ViewSrg::m_exposureControl.m_eyeAdaptationEnabled)
|
|
{
|
|
// Get the dimensions and mip levels from the luminance mip chain
|
|
uint2 inputDimensions;
|
|
uint numMipLevels = 1;
|
|
PassSrg::m_sceneLuminance.GetDimensions(0, inputDimensions.x, inputDimensions.y, numMipLevels);
|
|
|
|
// Use smallest 1x1 mip to get scene average luminance.
|
|
float luminanceAvg = PassSrg::m_sceneLuminance.SampleLevel(PassSrg::LinearSampler, float2(0.5f, 0.5f), numMipLevels - 1).y;
|
|
|
|
// Middle gray value is the half-tone between black and white in exposure control.
|
|
// Defining Middle Grey value to 0.18f as the typical value used in photography. Cf. https://en.wikipedia.org/wiki/Middle_gray
|
|
const float middleGray = 0.18f;
|
|
|
|
// Protection from NaNs getting in the frame buffer leading to NaN luminance.
|
|
if (isnan(luminanceAvg))
|
|
{
|
|
luminanceAvg = middleGray;
|
|
}
|
|
|
|
// This finds the exposure at which the lumininaceAvg would be equal to middleGray, ie perfectly neutral.
|
|
goalExposureLog2 = log2(luminanceAvg / middleGray);
|
|
|
|
// Clamp goal exposure by min / max.
|
|
float minExposure = ViewSrg::m_exposureControl.m_exposureMinLog2;
|
|
float maxExposure = ViewSrg::m_exposureControl.m_exposureMaxLog2;
|
|
goalExposureLog2 = clamp(goalExposureLog2, minExposure, maxExposure);
|
|
}
|
|
|
|
// Convert the previous frame linear exposure to a stop adjustment.
|
|
float previousFrameExposureLog2 = -log2(max(0.00000001, PassSrg::m_eyeAdaptationData[0].m_exposureValue));
|
|
|
|
float exposureDifference = goalExposureLog2 - previousFrameExposureLog2;
|
|
|
|
// Speed depends on if the exposure should be increased or decreased.
|
|
const float speed = exposureDifference > 0.0 ? ViewSrg::m_exposureControl.m_speedUp : ViewSrg::m_exposureControl.m_speedDown;
|
|
|
|
// Update the adjustment for this frame based on the frame deltaTime and speed
|
|
float deltaTime = clamp(SceneSrg::m_time - PassSrg::m_eyeAdaptationData[0].m_setValueTime, 0.0f, 1.0f);
|
|
float exposureAdjustment = exposureDifference * deltaTime * speed;
|
|
float newExposureLog2 = previousFrameExposureLog2 + exposureAdjustment;
|
|
|
|
// Store the linear exposure so it can be used by the look modification transform later.
|
|
// newExposureLog2 is negated because m_exposureValue is used to correct for a given exposure.
|
|
PassSrg::m_eyeAdaptationData[0].m_exposureValue = pow(2.0f, -newExposureLog2);
|
|
PassSrg::m_eyeAdaptationData[0].m_setValueTime = SceneSrg::m_time;
|
|
}
|