1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- /*
- * 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_all.srgi>
- #include <viewsrg_all.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;
- }
|