From 68acb9c8b0a504895e1e590c2e599bb73e3d32bb Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 22 Apr 2020 13:26:58 +0200 Subject: [PATCH 01/27] some very incomplete stuff... --- .../PostProcessing/Shaders/Exposure.compute | 96 +------- .../Shaders/ExposureCommon.hlsl | 103 +++++++++ .../Shaders/ExposureCommon.hlsl.meta | 10 + .../Shaders/HistogramExposure.compute | 207 ++++++++++++++++++ .../Shaders/HistogramExposure.compute.meta | 9 + .../RenderPipeline/HDStringConstants.cs | 1 + .../RenderPipeline/RenderPipelineResources.cs | 2 + 7 files changed, 335 insertions(+), 93 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute index 24bb51c8249..ca26aef5dce 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute @@ -1,7 +1,4 @@ -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/PhysicalCamera.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" #pragma only_renderers d3d11 playstation xboxone vulkan metal switch @@ -12,98 +9,11 @@ #pragma kernel KReset TEXTURE2D(_ExposureCurveTexture); -TEXTURE2D(_PreviousExposureTexture); TEXTURE2D(_InputTexture); -TEXTURE2D(_ExposureWeightMask); - -TEXTURE2D_X(_SourceTexture); RW_TEXTURE2D(float2, _OutputTexture); -SAMPLER(sampler_LinearClamp); - -CBUFFER_START(cb) - float4 _ExposureParams; - float4 _AdaptationParams; - uint4 _Variants; -CBUFFER_END - -#define ParamEV100 _ExposureParams.y -#define ParamExposureCompensation _ExposureParams.x -#define ParamAperture _ExposureParams.y -#define ParamShutterSpeed _ExposureParams.z -#define ParamISO _ExposureParams.w -#define ParamSpeedLightToDark _AdaptationParams.x -#define ParamSpeedDarkToLight _AdaptationParams.y -#define ParamExposureLimitMin _ExposureParams.y -#define ParamExposureLimitMax _ExposureParams.z -#define ParamCurveMin _ExposureParams.y -#define ParamCurveMax _ExposureParams.z -#define ParamSourceBuffer _Variants.x -#define ParamMeteringMode _Variants.y -#define ParamAdaptationMode _Variants.z -#define ParamEvaluateMode _Variants.w - -#define PREPASS_TEX_SIZE 1024.0 -#define PREPASS_TEX_HALF_SIZE 512.0 - -float WeightSample(uint2 pixel) -{ - UNITY_BRANCH - switch (ParamMeteringMode) - { - case 1u: - { - // Spot metering - const float kRadius = 0.075 * PREPASS_TEX_SIZE; - const float2 kCenter = (PREPASS_TEX_HALF_SIZE).xx; - float d = length(kCenter - pixel) - kRadius; - return 1.0 - saturate(d); - } - case 2u: - { - // Center-weighted - const float2 kCenter = (PREPASS_TEX_HALF_SIZE).xx; - return 1.0 - saturate(pow(length(kCenter - pixel) / PREPASS_TEX_HALF_SIZE, 1.0)); - } - case 3u: - { - // Mask weigthing - return SAMPLE_TEXTURE2D_LOD(_ExposureWeightMask, sampler_LinearClamp, pixel * rcp(PREPASS_TEX_SIZE), 0.0).x; - } - - default: - { - // Global average - return 1.0; - } - } -} - -float GetPreviousExposureEV100() -{ - return _PreviousExposureTexture[uint2(0u, 0u)].y; -} - -float AdaptExposure(float exposure) -{ - UNITY_BRANCH - switch (ParamAdaptationMode) - { - case 1u: - { - // Progressive - return ComputeLuminanceAdaptation(GetPreviousExposureEV100(), exposure, ParamSpeedDarkToLight, ParamSpeedLightToDark, unity_DeltaTime.x); - } - default: - { - // Fixed - return exposure; - } - } -} - // // Fixed exposure // Doesn't do anything fancy, simply copies the exposure & clamp values set in the volume system @@ -149,7 +59,7 @@ void KPrePass(uint2 dispatchThreadId : SV_DispatchThreadID) { // Color buffer float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, sampler_LinearClamp, uv, 0.0).xyz; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; luma = Luminance(color / prevExposure); break; } @@ -236,7 +146,7 @@ void KReduction(uint2 groupId : SV_GroupID, uint2 groupThreadId : SV_GroupThread { // Curve remapping float remap = saturate((avgLuminance - ParamCurveMin) / (ParamCurveMax - ParamCurveMin)); - float exposure = SAMPLE_TEXTURE2D_LOD(_ExposureCurveTexture, sampler_LinearClamp, float2(remap, 0.0), 0.0).x; + float exposure = SAMPLE_TEXTURE2D_LOD(_ExposureCurveTexture, s_linear_clamp_sampler, float2(remap, 0.0), 0.0).x; exposure = AdaptExposure(exposure - ParamExposureCompensation); _OutputTexture[groupId.xy] = float2(ConvertEV100ToExposure(exposure), exposure); break; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl new file mode 100644 index 00000000000..f108101666f --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl @@ -0,0 +1,103 @@ +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/PhysicalCamera.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + +TEXTURE2D(_ExposureWeightMask); +TEXTURE2D_X(_SourceTexture); +TEXTURE2D(_PreviousExposureTexture); + +CBUFFER_START(cb) +float4 _ExposureParams; +float4 _HistogramExposureParams; +float4 _AdaptationParams; +uint4 _Variants; +CBUFFER_END + +#define ParamEV100 _ExposureParams.y +#define ParamExposureCompensation _ExposureParams.x +#define ParamAperture _ExposureParams.y +#define ParamShutterSpeed _ExposureParams.z +#define ParamISO _ExposureParams.w +#define ParamSpeedLightToDark _AdaptationParams.x +#define ParamSpeedDarkToLight _AdaptationParams.y +#define ParamExposureLimitMin _ExposureParams.y +#define ParamExposureLimitMax _ExposureParams.z +#define ParamCurveMin _ExposureParams.y +#define ParamCurveMax _ExposureParams.z +#define ParamSourceBuffer _Variants.x +#define ParamMeteringMode _Variants.y +#define ParamAdaptationMode _Variants.z +#define ParamEvaluateMode _Variants.w + +// TODO_FCC: IMPORTANT! This function uses hard coded values for the texture that is output by the prepass. +// Need to make the analytical metering texture size independent. +// When that is done, these defines should be moved back to Exposure.compute +#define PREPASS_TEX_SIZE 1024.0 +#define PREPASS_TEX_HALF_SIZE 512.0 + + +float GetPreviousExposureEV100() +{ + return _PreviousExposureTexture[uint2(0u, 0u)].y; +} + +float WeightSample(uint2 pixel) +{ + UNITY_BRANCH + switch (ParamMeteringMode) + { + case 1u: + { + // Spot metering + const float kRadius = 0.075 * PREPASS_TEX_SIZE; + const float2 kCenter = (PREPASS_TEX_HALF_SIZE).xx; + float d = length(kCenter - pixel) - kRadius; + return 1.0 - saturate(d); + } + case 2u: + { + // Center-weighted + const float2 kCenter = (PREPASS_TEX_HALF_SIZE).xx; + return 1.0 - saturate(pow(length(kCenter - pixel) / PREPASS_TEX_HALF_SIZE, 1.0)); + } + case 3u: + { + // Mask weigthing + return SAMPLE_TEXTURE2D_LOD(_ExposureWeightMask, s_linear_clamp_sampler, pixel * rcp(PREPASS_TEX_SIZE), 0.0).x; + } + + default: + { + // Global average + return 1.0; + } + } +} + +float SampleLuminance(float2 uv) +{ + if (ParamSourceBuffer == 1) + { + // Color buffer + float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); + float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + return Luminance(color / prevExposure); + } + else + { + return 1.0f; + } +} + +float AdaptExposure(float exposure) +{ + if (ParamAdaptationMode == 1) + { + return ComputeLuminanceAdaptation(GetPreviousExposureEV100(), exposure, ParamSpeedDarkToLight, ParamSpeedLightToDark, unity_DeltaTime.x); + } + else + { + return exposure; + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl.meta new file mode 100644 index 00000000000..fd95688bcc3 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: cb6a39236cce6824cbf70aa0d69f39f6 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute new file mode 100644 index 00000000000..6951cee161c --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -0,0 +1,207 @@ +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" + +// TODO List to investigate +// - Number of bins: +// - Worth considering multiple histograms per lane in the thread. (i.e. sharedHisto[BINS][NUMB_HIST] ) +// - Worth checking the optimal group size. +// - At the moment the dispatch is at half res, but the buffer sampled is full res, +// causing fairly bad cache behaviour. Can we use the mip chain realistically without issues? [The one we have is blurred and might be incomplete?] + +// NOTE: fairly naive for now. + +// TODO: If we keep 128, we should have a group that is 128 threads. We can dispatch 128, 1, 1 and remap to get pixel. + +// TODO: IMPORTANT TODO_FCC [1] Do the bin calculations in ev100 instead of log2? Or work in luminance and convert later (As it is now)? + +#pragma kernel KHistogramGen GEN_PASS +#pragma kernel KHistogramReduce REDUCE_PASS + +#define _HistogramRangeScale _HistogramExposureParams.x +#define _HistogramRangeBias _HistogramExposureParams.y +#define _HistogramMinPercentage _HistogramExposureParams.z +#define _HistogramMaxPercentage _HistogramExposureParams.w + + +#define HISTOGRAM_BINS 256 // IMPORTANT: If this number is changed, the code needs adapting, I tried to add relevant comments to indicate where. +#define GROUP_SIZE 16 + +#ifdef GEN_PASS +RWStructuredBuffer _HistogramBuffer; +#else +StructuredBuffer _HistogramBuffer; +#endif + +// Because atomics are only on uint and we need a weighted value, we need to convert. +// Note that using 9bit per weight (allowing [0 ... 2] for weights), we can store up to 8388608 +// values per bin which is a bit more than all pixels of a 4K input image. +uint PackWeight(float weight) +{ + const uint numBits = 9; + + float processedWeight = clamp(weight, 0.0, 2.0) * 0.5f; + uint maxInt = (1u << numBits) - 1u; + return (uint)(processedWeight * maxInt + 0.5); +} + +float UnpackWeight(uint val) +{ + const uint numBits = 9; + uint maxInt = (1u << numBits) - 1u; + return saturate(val * rcp(maxInt)) * 2.0f; +} + +uint GetHistogramBinLocation(float value) +{ + float scaledLogLuma = log2(value) * _HistogramRangeScale + _HistogramRangeBias; + return uint(saturate(scaledLogLuma) * (HISTOGRAM_BINS - 1)); +} + +float BinLocationToLogLuma(uint binIdx) +{ + return (float(binIdx) - _HistogramRangeBias) / _HistogramRangeScale; +} + +groupshared uint gs_localHistogram[HISTOGRAM_BINS]; + + +// TODO_FCC: IMPORTANT TODO BEFORE PR: +// It is a bit awkward that we have more lanes than bins... +// If we keep this it is IMPERATIVE to have some guarantee on the coherency of the branch. + +[numthreads(GROUP_SIZE, GROUP_SIZE, 1)] +void KHistogramGen(uint groupIndex : SV_GroupIndex, + uint3 dispatchThreadId : SV_DispatchThreadID) +{ + // Groupshared memory is not guaranteed to be 0 initialized. + if (groupIndex < HISTOGRAM_BINS) + { + gs_localHistogram[groupIndex] = 0u; + } + + GroupMemoryBarrierWithGroupSync(); + + // IMPORTANT TODO: This leads to poor cache behaviour, verify if we can use lower mip of the color pyramid. + uint2 fullResCoords = dispatchThreadId.xy << 1u; + + if (all(fullResCoords < uint2(_ScreenSize.xy))) + { + float2 uv = ClampAndScaleUVForBilinear((fullResCoords + 0.5) * _ScreenSize.zw); + float luminance = SampleLuminance(uv); + float weight = WeightSample(uv); + + uint bin = GetHistogramBinLocation(luminance); + + InterlockedAdd(gs_localHistogram[bin], PackWeight(weight)); + } + + GroupMemoryBarrierWithGroupSync(); + + if (groupIndex < HISTOGRAM_BINS) + { + InterlockedAdd(_HistogramBuffer[groupIndex], gs_localHistogram[groupIndex]); + } +} + +#define USE_WAVE_INTRINSICS defined(PLATFORM_LANE_COUNT) && defined(PLATFORM_SUPPORTS_WAVE_INTRINSICS) + + +#if USE_WAVE_INTRINSICS + +#define WAVE_SIZE PLATFORM_LANE_COUNT +#define SUM_SCRATCH_SIZE HISTOGRAM_BINS / WAVE_SIZE + +#else + +#define SUM_SCRATCH_SIZE HISTOGRAM_BINS + +#endif + +groupshared float gs_partialSums[SUM_SCRATCH_SIZE]; +groupshared float gs_values[HISTOGRAM_BINS]; + +[numthreads(HISTOGRAM_BINS, 1, 1)] +void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) +{ + uint threadID = dispatchThreadId.x; + uint sum = 0; + float histogramVal = UnpackWeight(_HistogramBuffer[threadID]); + +#if USE_WAVE_INTRINSICS + + uint waveCount = (HISTOGRAM_BINS / WAVE_SIZE); + uint waveSum = WaveActiveSum(histogramVal); + + uint waveIDInGroup = threadID / WAVE_SIZE; + if (WaveIsFirstLane()) + { + gs_partialSums[waveIDInGroup] = waveSum; + } + + gs_values[threadID] = histogramVal; + + // We have values for all the waves, let's sync. + GroupMemoryBarrierWithGroupSync(); + + sum = gs_partialSums[0]; + for (uint i = 1u; i < waveCount; ++i) + { + sum += gs_partialSums[i]; + } + +#else // !USE_WAVE_INTRINSICS + + gs_values[threadID] = histogramVal; + gs_partialSums[threadID] = histogramVal; + + GroupMemoryBarrierWithGroupSync(); + + // Sum all values + for (uint i = (HISTOGRAM_BINS >> 1u); i > 0; i >>= 1u) + { + if (threadID < i) + { + gs_partialSums[threadID] += gs_partialSums[threadID + i]; + } + + GroupMemoryBarrierWithGroupSync(); + } + + sum = gs_partialSums[0]; + +#endif + + float2 extremesSums = float2(_HistogramMinPercentage, _HistogramMaxPercentage) * sum; + + // TODO: This can probably done more efficiently. Also verify that all but the first wave + // actually skip this or if we need to enforce it somehow. + if (threadID == 0) + { + float logProcessedSum = 0; + float w = 0; + + for (int i = 0; i < HISTOGRAM_BINS; ++i) + { + float histVal = gs_values[i]; + float binLogLuma = BinLocationToLogLuma(i); + + float off = min(extremesSums.x, histVal); + extremesSums -= off; + histVal -= off; + + histVal = min(extremesSums.y, histVal); + extremesSums.y -= histVal; + + logProcessedSum += histVal * binLogLuma; + w += histVal; + } + + w = max(w, 1e-4f); + float avgLuminance = logProcessedSum * rcp(w); + avgLuminance = exp2(avgLuminance); + + // TODO + + } + + +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute.meta new file mode 100644 index 00000000000..ec4511dfb0c --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 222da48299136f34b8e3fb75ae9f8ac7 +ComputeShaderImporter: + externalObjects: {} + currentAPIMask: 4 + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index f221e32003a..616dff1b136 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -596,6 +596,7 @@ static class HDShaderIDs public static readonly int _PrevExposureTexture = Shader.PropertyToID("_PrevExposureTexture"); public static readonly int _PreviousExposureTexture = Shader.PropertyToID("_PreviousExposureTexture"); public static readonly int _ExposureParams = Shader.PropertyToID("_ExposureParams"); + public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); public static readonly int _AdaptationParams = Shader.PropertyToID("_AdaptationParams"); public static readonly int _ExposureCurveTexture = Shader.PropertyToID("_ExposureCurveTexture"); public static readonly int _ExposureWeightMask = Shader.PropertyToID("_ExposureWeightMask"); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs index 1adb07ae3df..52d860f21e8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -213,6 +213,8 @@ public sealed class ShaderResources public ComputeShader nanKillerCS; [Reload("Runtime/PostProcessing/Shaders/Exposure.compute")] public ComputeShader exposureCS; + [Reload("Runtime/PostProcessing/Shaders/HistogramExposure.compute")] + public ComputeShader histogramExposureCS; [Reload("Runtime/PostProcessing/Shaders/ApplyExposure.compute")] public ComputeShader applyExposureCS; [Reload("Runtime/PostProcessing/Shaders/UberPost.compute")] From ccb3a842dc491c52aa6772a48b4759359ff0e836 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 23 Apr 2020 18:44:10 +0200 Subject: [PATCH 02/27] sync point, rough working version --- .../PostProcessing/Components/Exposure.cs | 18 +++- .../PostProcessing/PostProcessSystem.cs | 89 ++++++++++++++++++- .../PostProcessing/Shaders/Exposure.compute | 24 ++++- .../Shaders/ExposureCommon.hlsl | 17 ++-- .../Shaders/HistogramExposure.compute | 80 ++++++++++------- .../RenderPipeline/HDStringConstants.cs | 2 + 6 files changed, 182 insertions(+), 48 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs index 0007c9c6076..a2aafe0a720 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs @@ -86,11 +86,20 @@ public sealed class Exposure : VolumeComponent, IPostProcessComponent public MinFloatParameter adaptationSpeedLightToDark = new MinFloatParameter(1f, 0.001f); /// - /// Sets the texture mask used to weight the pixels in the buffer when computing exposure. Used only with . + /// Sets the texture mask used to weight the pixels in the buffer when computing exposure. /// - [Tooltip("Sets the texture mask to be used to weight the pixels in the buffer for the sake of computing exposure..")] + [Tooltip("Sets the texture mask to be used to weight the pixels in the buffer for the sake of computing exposure.")] public NoInterpTextureParameter weightTextureMask = new NoInterpTextureParameter(null); + + /// + /// These values are the lower and upper percentages of the histogram that will be used to + /// find a stable average luminance. Values outside of this range will be discarded and won't + /// contribute to the average luminance. + /// + [Tooltip("Sets the range of values (in terms of percentages) of the histogram that are accepted while finding a stable average exposure. Anything outside the value is discarded.")] + public FloatRangeParameter histogramPercentages = new FloatRangeParameter(new Vector2(50.0f, 90.0f), 0.001f, 100.0f); + /// /// Tells if the effect needs to be rendered or not. /// @@ -117,6 +126,11 @@ public enum ExposureMode /// Automatic, + /// + /// Automatically sets the exposure depending on what is on screen and can filter out outliers based on provided settings. + /// + AutomaticHistogram, + /// /// Maps the current Scene exposure to a custom curve. /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index a3d37de005c..eaf92f97711 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -34,11 +34,14 @@ private enum SMAAStage // Exposure data const int k_ExposureCurvePrecision = 128; + const int k_HistogramBins = 128; // Important! If this changes, need to change HistogramExposure.compute readonly Color[] m_ExposureCurveColorArray = new Color[k_ExposureCurvePrecision]; readonly int[] m_ExposureVariants = new int[4]; Texture2D m_ExposureCurveTexture; RTHandle m_EmptyExposureTexture; // RGHalf + ComputeBuffer m_HistogramBuffer; + readonly int[] m_EmptyHistogram = new int[k_HistogramBins]; // Depth of field data ComputeBuffer m_BokehNearKernel; @@ -242,6 +245,7 @@ public void Cleanup() RTHandles.Release(m_TempTexture32); RTHandles.Release(m_AlphaTexture); CoreUtils.Destroy(m_ExposureCurveTexture); + CoreUtils.SafeRelease(m_HistogramBuffer); CoreUtils.Destroy(m_InternalSpectralLut); RTHandles.Release(m_InternalLogLut); CoreUtils.Destroy(m_FinalPassMaterial); @@ -260,6 +264,7 @@ public void Cleanup() m_TempTexture32 = null; m_AlphaTexture = null; m_ExposureCurveTexture = null; + m_HistogramBuffer = null; m_InternalSpectralLut = null; m_InternalLogLut = null; m_FinalPassMaterial = null; @@ -453,7 +458,13 @@ void PoolSource(ref RTHandle src, RTHandle dst) { using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.DynamicExposure))) { - DoDynamicExposure(cmd, camera, source); + if (m_Exposure.mode.value == ExposureMode.AutomaticHistogram) + { + DoHistogramBasedExposure(cmd, camera, source); + // m_Exposure.mode.value = ExposureMode.Automatic; + } + else + DoDynamicExposure(cmd, camera, source); // On reset history we need to apply dynamic exposure immediately to avoid // white or black screen flashes when the current exposure isn't anywhere @@ -914,6 +925,82 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) cmd.DispatchCompute(cs, kernel, 1, 1, 1); } + void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourceTexture) + { + var cs = m_Resources.shaders.histogramExposureCS; + int kernel; + + GrabExposureHistoryTextures(camera, out var prevExposure, out var nextExposure); + + var debug = m_Pool.Get(Vector2.one * 0.5f, GraphicsFormat.R32G32B32A32_SFloat); + + // Setup variants + var adaptationMode = m_Exposure.adaptationMode.value; + + if (!Application.isPlaying || camera.resetPostProcessingHistory) + adaptationMode = AdaptationMode.Fixed; + + if (camera.resetPostProcessingHistory) + { + // For Dynamic Exposure, we need to undo the pre-exposure from the color buffer to calculate the correct one + // When we reset history we must setup neutral value + prevExposure = m_EmptyExposureTexture; // Use neutral texture + } + + m_ExposureVariants[0] = 1; // (int)exposureSettings.luminanceSource.value; + m_ExposureVariants[1] = (int)m_Exposure.meteringMode.value; + m_ExposureVariants[2] = (int)adaptationMode; + m_ExposureVariants[3] = 0; + + // Parameters + Vector2 histogramFraction = m_Exposure.histogramPercentages.value / 100.0f; + float evRange = m_Exposure.limitMax.value - m_Exposure.limitMin.value; + float histScale = 1.0f / evRange; + float histBias = -m_Exposure.limitMin.value * histScale; + Vector4 histogramParams = new Vector4(histScale, histBias, histogramFraction.x, histogramFraction.y); + + ValidateComputeBuffer(ref m_HistogramBuffer, k_HistogramBins, sizeof(uint)); + m_HistogramBuffer.SetData(m_EmptyHistogram); // Clear the histogram + cmd.SetComputeVectorParam(cs, HDShaderIDs._HistogramExposureParams, histogramParams); + + // Generate histogram. + kernel = cs.FindKernel("KHistogramGen"); + cmd.SetComputeIntParams(cs, HDShaderIDs._Variants, m_ExposureVariants); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._SourceTexture, sourceTexture); + if (m_Exposure.meteringMode == MeteringMode.MaskWeighted && m_Exposure.weightTextureMask.value != null) + { + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureWeightMask, m_Exposure.weightTextureMask.value); + } + else + { + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureWeightMask, Texture2D.whiteTexture); + } + + cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs._HistogramBuffer, m_HistogramBuffer); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._TODO_REMOVE_ME, debug); + + int threadGroupSizeX = 16; + int threadGroupSizeY = 8; + int dispatchSizeX = HDUtils.DivRoundUp(camera.actualWidth / 2, threadGroupSizeX); + int dispatchSizeY = HDUtils.DivRoundUp(camera.actualHeight / 2, threadGroupSizeY); + int totalPixels = camera.actualWidth * camera.actualHeight; + cmd.DispatchCompute(cs, kernel, dispatchSizeX, dispatchSizeY, 1); + + // Now read the histogram + kernel = cs.FindKernel("KHistogramReduce"); + cmd.SetComputeVectorParam(cs, HDShaderIDs._ExposureParams, new Vector4(m_Exposure.compensation.value + m_DebugExposureCompensation, m_Exposure.limitMin.value, m_Exposure.limitMax.value, 0f)); + cmd.SetComputeVectorParam(cs, HDShaderIDs._AdaptationParams, new Vector4(m_Exposure.adaptationSpeedLightToDark.value, m_Exposure.adaptationSpeedDarkToLight.value, 0f, 0f)); + cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs._HistogramBuffer, m_HistogramBuffer); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._OutputTexture, nextExposure); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._TODO_REMOVE_ME, debug); + + cmd.DispatchCompute(cs, kernel, 1, 1, 1); + + m_Pool.Recycle(debug); + } + #endregion #region Temporal Anti-aliasing diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute index ca26aef5dce..7e0c2583ed8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute @@ -11,8 +11,10 @@ TEXTURE2D(_ExposureCurveTexture); TEXTURE2D(_InputTexture); +#pragma enable_d3d11_debug_symbols -RW_TEXTURE2D(float2, _OutputTexture); +#define PREPASS_TEX_SIZE 1024.0 +#define PREPASS_TEX_HALF_SIZE 512.0 // // Fixed exposure @@ -38,6 +40,20 @@ void KManualCameraExposure(uint2 dispatchThreadId : SV_DispatchThreadID) _OutputTexture[dispatchThreadId] = float2(ConvertEV100ToExposure(ev100), ev100); } + +uint GetHistogramBinLocation(float value) +{ + float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * 0.0333333333f + 0.33333333333; + return uint(saturate(scaledLogLuma) * (128 - 1)); +} + +float BinLocationToLogLuma(uint binIdx) +{ + return (binIdx * rcp(float(128 - 1)) - 0.33333333333) / 0.0333333333f; +} + + + // // Average luminance pre-pass // Transforms the input to log luminance in a square-POT target @@ -71,9 +87,11 @@ void KPrePass(uint2 dispatchThreadId : SV_DispatchThreadID) } } - float weight = WeightSample(dispatchThreadId); + float weight = WeightSample(dispatchThreadId, PREPASS_TEX_SIZE.xx); + uint bin = GetHistogramBinLocation(luma); + float value = BinLocationToLogLuma(bin); float logLuma = ComputeEV100FromAvgLuminance(max(luma, 1e-4)); - _OutputTexture[posInputs.positionSS] = float2(logLuma, weight); + _OutputTexture[posInputs.positionSS] = float2(value, weight); } // diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl index f108101666f..a91c2093fe4 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl @@ -6,6 +6,7 @@ TEXTURE2D(_ExposureWeightMask); TEXTURE2D_X(_SourceTexture); TEXTURE2D(_PreviousExposureTexture); +RW_TEXTURE2D(float2, _OutputTexture); CBUFFER_START(cb) float4 _ExposureParams; @@ -33,8 +34,6 @@ CBUFFER_END // TODO_FCC: IMPORTANT! This function uses hard coded values for the texture that is output by the prepass. // Need to make the analytical metering texture size independent. // When that is done, these defines should be moved back to Exposure.compute -#define PREPASS_TEX_SIZE 1024.0 -#define PREPASS_TEX_HALF_SIZE 512.0 float GetPreviousExposureEV100() @@ -42,7 +41,7 @@ float GetPreviousExposureEV100() return _PreviousExposureTexture[uint2(0u, 0u)].y; } -float WeightSample(uint2 pixel) +float WeightSample(uint2 pixel, float2 sourceSize) { UNITY_BRANCH switch (ParamMeteringMode) @@ -50,21 +49,23 @@ float WeightSample(uint2 pixel) case 1u: { // Spot metering - const float kRadius = 0.075 * PREPASS_TEX_SIZE; - const float2 kCenter = (PREPASS_TEX_HALF_SIZE).xx; + float screenDiagonal = 0.5f * (sourceSize.x + sourceSize.y); + const float kRadius = 0.075 * screenDiagonal; + const float2 kCenter = sourceSize * 0.5f; float d = length(kCenter - pixel) - kRadius; return 1.0 - saturate(d); } case 2u: { // Center-weighted - const float2 kCenter = (PREPASS_TEX_HALF_SIZE).xx; - return 1.0 - saturate(pow(length(kCenter - pixel) / PREPASS_TEX_HALF_SIZE, 1.0)); + float screenDiagonal = 0.5f * (sourceSize.x + sourceSize.y); + const float2 kCenter = sourceSize * 0.5f; + return 1.0 - saturate(pow(length(kCenter - pixel) / screenDiagonal, 1.0)); } case 3u: { // Mask weigthing - return SAMPLE_TEXTURE2D_LOD(_ExposureWeightMask, s_linear_clamp_sampler, pixel * rcp(PREPASS_TEX_SIZE), 0.0).x; + return SAMPLE_TEXTURE2D_LOD(_ExposureWeightMask, s_linear_clamp_sampler, pixel * rcp(sourceSize), 0.0).x; } default: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index 6951cee161c..ac94d2fa5b6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -1,5 +1,7 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" +#pragma enable_d3d11_debug_symbols + // TODO List to investigate // - Number of bins: // - Worth considering multiple histograms per lane in the thread. (i.e. sharedHisto[BINS][NUMB_HIST] ) @@ -9,21 +11,21 @@ // NOTE: fairly naive for now. -// TODO: If we keep 128, we should have a group that is 128 threads. We can dispatch 128, 1, 1 and remap to get pixel. +// TODO: Do mapping to 0.18 instead of 1 ? -// TODO: IMPORTANT TODO_FCC [1] Do the bin calculations in ev100 instead of log2? Or work in luminance and convert later (As it is now)? #pragma kernel KHistogramGen GEN_PASS #pragma kernel KHistogramReduce REDUCE_PASS -#define _HistogramRangeScale _HistogramExposureParams.x -#define _HistogramRangeBias _HistogramExposureParams.y +#define _HistogramRangeScale _HistogramExposureParams.x +#define _HistogramRangeBias _HistogramExposureParams.y #define _HistogramMinPercentage _HistogramExposureParams.z #define _HistogramMaxPercentage _HistogramExposureParams.w -#define HISTOGRAM_BINS 256 // IMPORTANT: If this number is changed, the code needs adapting, I tried to add relevant comments to indicate where. -#define GROUP_SIZE 16 +#define HISTOGRAM_BINS 128 // IMPORTANT: If this number is changed, the code needs adapting, I tried to add relevant comments to indicate where. +#define GROUP_SIZE_X 16 +#define GROUP_SIZE_Y 8 #ifdef GEN_PASS RWStructuredBuffer _HistogramBuffer; @@ -31,49 +33,47 @@ RWStructuredBuffer _HistogramBuffer; StructuredBuffer _HistogramBuffer; #endif +// TODO_FCC: REMOVE THIS IS DEBUG. +RW_TEXTURE2D_X(float4, _TODO_REMOVE_ME); + + // Because atomics are only on uint and we need a weighted value, we need to convert. -// Note that using 9bit per weight (allowing [0 ... 2] for weights), we can store up to 8388608 -// values per bin which is a bit more than all pixels of a 4K input image. +// If we multiply the weight by 2048, we get somewhat ok precision and we support up to +// the equivalent of 1920x1080 image in one bin. (Note, we run this at half res, so equivalent of 4k image) uint PackWeight(float weight) { - const uint numBits = 9; - - float processedWeight = clamp(weight, 0.0, 2.0) * 0.5f; - uint maxInt = (1u << numBits) - 1u; - return (uint)(processedWeight * maxInt + 0.5); + return uint(weight * 2048); } float UnpackWeight(uint val) { - const uint numBits = 9; - uint maxInt = (1u << numBits) - 1u; - return saturate(val * rcp(maxInt)) * 2.0f; + return val * rcp(2048.0f); } uint GetHistogramBinLocation(float value) { - float scaledLogLuma = log2(value) * _HistogramRangeScale + _HistogramRangeBias; + float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * _HistogramRangeScale + _HistogramRangeBias; return uint(saturate(scaledLogLuma) * (HISTOGRAM_BINS - 1)); } float BinLocationToLogLuma(uint binIdx) { - return (float(binIdx) - _HistogramRangeBias) / _HistogramRangeScale; + return (binIdx * rcp(float(HISTOGRAM_BINS - 1)) - _HistogramRangeBias) / _HistogramRangeScale; } groupshared uint gs_localHistogram[HISTOGRAM_BINS]; // TODO_FCC: IMPORTANT TODO BEFORE PR: -// It is a bit awkward that we have more lanes than bins... // If we keep this it is IMPERATIVE to have some guarantee on the coherency of the branch. -[numthreads(GROUP_SIZE, GROUP_SIZE, 1)] +[numthreads(GROUP_SIZE_X, GROUP_SIZE_Y, 1)] void KHistogramGen(uint groupIndex : SV_GroupIndex, uint3 dispatchThreadId : SV_DispatchThreadID) { - // Groupshared memory is not guaranteed to be 0 initialized. - if (groupIndex < HISTOGRAM_BINS) + // Groupshared memory is not guaranteed to be 0 initialized. + // Note that currently the branch is always true (GROUP_SIZE_X * GROUP_SIZE_Y == HISTOGRAM_BINS). Here as safeguard if changing group size or bins. + if (groupIndex < HISTOGRAM_BINS) { gs_localHistogram[groupIndex] = 0u; } @@ -87,13 +87,16 @@ void KHistogramGen(uint groupIndex : SV_GroupIndex, { float2 uv = ClampAndScaleUVForBilinear((fullResCoords + 0.5) * _ScreenSize.zw); float luminance = SampleLuminance(uv); - float weight = WeightSample(uv); + float weight = WeightSample(fullResCoords, _ScreenSize.xy); uint bin = GetHistogramBinLocation(luminance); + _TODO_REMOVE_ME[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = float4((float)bin, weight, luminance, (log2(luminance) * _HistogramRangeScale + _HistogramRangeBias) * (HISTOGRAM_BINS - 1)); + InterlockedAdd(gs_localHistogram[bin], PackWeight(weight)); } + GroupMemoryBarrierWithGroupSync(); if (groupIndex < HISTOGRAM_BINS) @@ -119,17 +122,18 @@ void KHistogramGen(uint groupIndex : SV_GroupIndex, groupshared float gs_partialSums[SUM_SCRATCH_SIZE]; groupshared float gs_values[HISTOGRAM_BINS]; + [numthreads(HISTOGRAM_BINS, 1, 1)] void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) { uint threadID = dispatchThreadId.x; - uint sum = 0; + float sum = 0; float histogramVal = UnpackWeight(_HistogramBuffer[threadID]); #if USE_WAVE_INTRINSICS uint waveCount = (HISTOGRAM_BINS / WAVE_SIZE); - uint waveSum = WaveActiveSum(histogramVal); + float waveSum = WaveActiveSum(histogramVal); uint waveIDInGroup = threadID / WAVE_SIZE; if (WaveIsFirstLane()) @@ -156,12 +160,10 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) GroupMemoryBarrierWithGroupSync(); // Sum all values - for (uint i = (HISTOGRAM_BINS >> 1u); i > 0; i >>= 1u) + for (uint i = HISTOGRAM_BINS >> 1u; i > 0u; i >>= 1u) { if (threadID < i) - { - gs_partialSums[threadID] += gs_partialSums[threadID + i]; - } + gs_partialSums[threadID] = (gs_partialSums[threadID] + gs_partialSums[threadID + i]); GroupMemoryBarrierWithGroupSync(); } @@ -176,13 +178,18 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) // actually skip this or if we need to enforce it somehow. if (threadID == 0) { - float logProcessedSum = 0; + float evProcessedSum = 0; float w = 0; + // Delete + float simpleSum = 0; + float simpleLumaSum = 0; for (int i = 0; i < HISTOGRAM_BINS; ++i) { float histVal = gs_values[i]; + simpleSum += histVal; float binLogLuma = BinLocationToLogLuma(i); + simpleLumaSum += histVal * binLogLuma; float off = min(extremesSums.x, histVal); extremesSums -= off; @@ -191,15 +198,20 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) histVal = min(extremesSums.y, histVal); extremesSums.y -= histVal; - logProcessedSum += histVal * binLogLuma; + evProcessedSum += histVal * binLogLuma; w += histVal; + + _TODO_REMOVE_ME[uint3(i+1, 0, 0)] = float4(evProcessedSum, histVal, binLogLuma, simpleLumaSum / simpleSum); + } w = max(w, 1e-4f); - float avgLuminance = logProcessedSum * rcp(w); - avgLuminance = exp2(avgLuminance); + float avgEV = evProcessedSum * rcp(w); - // TODO + float exposure = AdaptExposure(avgEV - ParamExposureCompensation); + exposure = clamp(exposure, ParamExposureLimitMin, ParamExposureLimitMax); + _TODO_REMOVE_ME[uint3(0, 0, 0)] = float4(evProcessedSum, w, avgEV, exposure); + _OutputTexture[uint2(0,0)] = float2(ConvertEV100ToExposure(exposure), exposure); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index 616dff1b136..d542e9bc211 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -597,6 +597,8 @@ static class HDShaderIDs public static readonly int _PreviousExposureTexture = Shader.PropertyToID("_PreviousExposureTexture"); public static readonly int _ExposureParams = Shader.PropertyToID("_ExposureParams"); public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); + public static readonly int _HistogramBuffer = Shader.PropertyToID("_HistogramBuffer"); + public static readonly int _TODO_REMOVE_ME = Shader.PropertyToID("_TODO_REMOVE_ME"); public static readonly int _AdaptationParams = Shader.PropertyToID("_AdaptationParams"); public static readonly int _ExposureCurveTexture = Shader.PropertyToID("_ExposureCurveTexture"); public static readonly int _ExposureWeightMask = Shader.PropertyToID("_ExposureWeightMask"); From 297f0d4e1920d1196c6777ae497f22578e13b281 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 24 Apr 2020 11:55:21 +0200 Subject: [PATCH 03/27] Mostly working for now, moving onto debug vis and maybe revisit. --- .../Editor/PostProcessing/ExposureEditor.cs | 21 ++++- .../PostProcessing/PostProcessSystem.cs | 8 +- .../Shaders/HistogramExposure.compute | 84 +++++++++---------- .../HDRenderPipelineResources.asset | 1 + 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs index a08652ed5d8..3622ceff329 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs @@ -1,4 +1,5 @@ using UnityEditor.Rendering; +using UnityEngine; using UnityEngine.Rendering.HighDefinition; namespace UnityEditor.Rendering.HighDefinition @@ -22,6 +23,8 @@ sealed class ExposureEditor : VolumeComponentEditor SerializedDataParameter m_WeightTextureMask; + SerializedDataParameter m_HistogramPercentages; + public override void OnEnable() { var o = new PropertyFetcher(serializedObject); @@ -41,6 +44,8 @@ public override void OnEnable() m_AdaptationSpeedLightToDark = Unpack(o.Find(x => x.adaptationSpeedLightToDark)); m_WeightTextureMask = Unpack(o.Find(x => x.weightTextureMask)); + + m_HistogramPercentages = Unpack(o.Find(x => x.histogramPercentages)); } public override void OnInspectorGUI() @@ -65,10 +70,11 @@ public override void OnInspectorGUI() if(m_MeteringMode.value.intValue == (int)MeteringMode.MaskWeighted) PropertyField(m_WeightTextureMask); - PropertyField(m_LuminanceSource); + // Temporary hiding the field since we don't support anything but color buffer for now. + //PropertyField(m_LuminanceSource); - if (m_LuminanceSource.value.intValue == (int)LuminanceSource.LightingBuffer) - EditorGUILayout.HelpBox("Luminance source buffer isn't supported yet.", MessageType.Warning); + //if (m_LuminanceSource.value.intValue == (int)LuminanceSource.LightingBuffer) + // EditorGUILayout.HelpBox("Luminance source buffer isn't supported yet.", MessageType.Warning); if (mode == (int)ExposureMode.CurveMapping) PropertyField(m_CurveMap); @@ -76,7 +82,14 @@ public override void OnInspectorGUI() PropertyField(m_Compensation); PropertyField(m_LimitMin); PropertyField(m_LimitMax); - + + if(mode == (int)ExposureMode.AutomaticHistogram) + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Histogram", EditorStyles.miniLabel); + PropertyField(m_HistogramPercentages); + } + EditorGUILayout.Space(); EditorGUILayout.LabelField("Adaptation", EditorStyles.miniLabel); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index eaf92f97711..e1d8a1aae60 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -932,8 +932,6 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc GrabExposureHistoryTextures(camera, out var prevExposure, out var nextExposure); - var debug = m_Pool.Get(Vector2.one * 0.5f, GraphicsFormat.R32G32B32A32_SFloat); - // Setup variants var adaptationMode = m_Exposure.adaptationMode.value; @@ -955,7 +953,7 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc // Parameters Vector2 histogramFraction = m_Exposure.histogramPercentages.value / 100.0f; float evRange = m_Exposure.limitMax.value - m_Exposure.limitMin.value; - float histScale = 1.0f / evRange; + float histScale = 1.0f / Mathf.Max(1e-5f, evRange); float histBias = -m_Exposure.limitMin.value * histScale; Vector4 histogramParams = new Vector4(histScale, histBias, histogramFraction.x, histogramFraction.y); @@ -978,7 +976,6 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc } cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs._HistogramBuffer, m_HistogramBuffer); - cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._TODO_REMOVE_ME, debug); int threadGroupSizeX = 16; int threadGroupSizeY = 8; @@ -994,11 +991,8 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs._HistogramBuffer, m_HistogramBuffer); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._OutputTexture, nextExposure); - cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._TODO_REMOVE_ME, debug); cmd.DispatchCompute(cs, kernel, 1, 1, 1); - - m_Pool.Recycle(debug); } #endregion diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index ac94d2fa5b6..01edbe68955 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -33,9 +33,6 @@ RWStructuredBuffer _HistogramBuffer; StructuredBuffer _HistogramBuffer; #endif -// TODO_FCC: REMOVE THIS IS DEBUG. -RW_TEXTURE2D_X(float4, _TODO_REMOVE_ME); - // Because atomics are only on uint and we need a weighted value, we need to convert. // If we multiply the weight by 2048, we get somewhat ok precision and we support up to @@ -56,7 +53,7 @@ uint GetHistogramBinLocation(float value) return uint(saturate(scaledLogLuma) * (HISTOGRAM_BINS - 1)); } -float BinLocationToLogLuma(uint binIdx) +float BinLocationToEV(uint binIdx) { return (binIdx * rcp(float(HISTOGRAM_BINS - 1)) - _HistogramRangeBias) / _HistogramRangeScale; } @@ -64,9 +61,6 @@ float BinLocationToLogLuma(uint binIdx) groupshared uint gs_localHistogram[HISTOGRAM_BINS]; -// TODO_FCC: IMPORTANT TODO BEFORE PR: -// If we keep this it is IMPERATIVE to have some guarantee on the coherency of the branch. - [numthreads(GROUP_SIZE_X, GROUP_SIZE_Y, 1)] void KHistogramGen(uint groupIndex : SV_GroupIndex, uint3 dispatchThreadId : SV_DispatchThreadID) @@ -80,7 +74,7 @@ void KHistogramGen(uint groupIndex : SV_GroupIndex, GroupMemoryBarrierWithGroupSync(); - // IMPORTANT TODO: This leads to poor cache behaviour, verify if we can use lower mip of the color pyramid. + // TODO: This leads to poor cache behaviour, verify if we can use lower mip of the color pyramid. uint2 fullResCoords = dispatchThreadId.xy << 1u; if (all(fullResCoords < uint2(_ScreenSize.xy))) @@ -90,15 +84,13 @@ void KHistogramGen(uint groupIndex : SV_GroupIndex, float weight = WeightSample(fullResCoords, _ScreenSize.xy); uint bin = GetHistogramBinLocation(luminance); - - _TODO_REMOVE_ME[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = float4((float)bin, weight, luminance, (log2(luminance) * _HistogramRangeScale + _HistogramRangeBias) * (HISTOGRAM_BINS - 1)); - InterlockedAdd(gs_localHistogram[bin], PackWeight(weight)); } GroupMemoryBarrierWithGroupSync(); + // Note that currently the branch is always true (GROUP_SIZE_X * GROUP_SIZE_Y == HISTOGRAM_BINS). Here as safeguard if changing group size or bins. if (groupIndex < HISTOGRAM_BINS) { InterlockedAdd(_HistogramBuffer[groupIndex], gs_localHistogram[groupIndex]); @@ -122,18 +114,14 @@ void KHistogramGen(uint groupIndex : SV_GroupIndex, groupshared float gs_partialSums[SUM_SCRATCH_SIZE]; groupshared float gs_values[HISTOGRAM_BINS]; - -[numthreads(HISTOGRAM_BINS, 1, 1)] -void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) +float ComputeTotalSum(uint threadID, float threadVal) { - uint threadID = dispatchThreadId.x; float sum = 0; - float histogramVal = UnpackWeight(_HistogramBuffer[threadID]); #if USE_WAVE_INTRINSICS uint waveCount = (HISTOGRAM_BINS / WAVE_SIZE); - float waveSum = WaveActiveSum(histogramVal); + float waveSum = WaveActiveSum(threadVal); uint waveIDInGroup = threadID / WAVE_SIZE; if (WaveIsFirstLane()) @@ -141,8 +129,6 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) gs_partialSums[waveIDInGroup] = waveSum; } - gs_values[threadID] = histogramVal; - // We have values for all the waves, let's sync. GroupMemoryBarrierWithGroupSync(); @@ -154,8 +140,7 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) #else // !USE_WAVE_INTRINSICS - gs_values[threadID] = histogramVal; - gs_partialSums[threadID] = histogramVal; + gs_partialSums[threadID] = threadVal; GroupMemoryBarrierWithGroupSync(); @@ -163,7 +148,7 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) for (uint i = HISTOGRAM_BINS >> 1u; i > 0u; i >>= 1u) { if (threadID < i) - gs_partialSums[threadID] = (gs_partialSums[threadID] + gs_partialSums[threadID + i]); + gs_partialSums[threadID] = (gs_partialSums[threadID] + gs_partialSums[threadID + i]); GroupMemoryBarrierWithGroupSync(); } @@ -172,6 +157,36 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) #endif + return sum; +} + +void ProcessBin(uint binIndex, inout float2 extremesSums, inout float evSum, inout float totalWeight) +{ + float histVal = gs_values[binIndex]; + float binEV = BinLocationToEV(binIndex); + + // Low values + float off = min(extremesSums.x, histVal); + extremesSums -= off; + histVal -= off; + // High values + histVal = min(extremesSums.y, histVal); + extremesSums.y -= histVal; + + evSum += histVal * binEV; + totalWeight += histVal; +} + +[numthreads(HISTOGRAM_BINS, 1, 1)] +void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) +{ + uint threadID = dispatchThreadId.x; + float histogramVal = UnpackWeight(_HistogramBuffer[threadID]); + + gs_values[threadID] = histogramVal; + + float sum = ComputeTotalSum(threadID, histogramVal); + float2 extremesSums = float2(_HistogramMinPercentage, _HistogramMaxPercentage) * sum; // TODO: This can probably done more efficiently. Also verify that all but the first wave @@ -180,29 +195,10 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) { float evProcessedSum = 0; float w = 0; - // Delete - float simpleSum = 0; - float simpleLumaSum = 0; for (int i = 0; i < HISTOGRAM_BINS; ++i) { - float histVal = gs_values[i]; - simpleSum += histVal; - float binLogLuma = BinLocationToLogLuma(i); - simpleLumaSum += histVal * binLogLuma; - - float off = min(extremesSums.x, histVal); - extremesSums -= off; - histVal -= off; - - histVal = min(extremesSums.y, histVal); - extremesSums.y -= histVal; - - evProcessedSum += histVal * binLogLuma; - w += histVal; - - _TODO_REMOVE_ME[uint3(i+1, 0, 0)] = float4(evProcessedSum, histVal, binLogLuma, simpleLumaSum / simpleSum); - + ProcessBin(i, extremesSums, evProcessedSum, w); } w = max(w, 1e-4f); @@ -210,9 +206,7 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) float exposure = AdaptExposure(avgEV - ParamExposureCompensation); exposure = clamp(exposure, ParamExposureLimitMin, ParamExposureLimitMax); - _TODO_REMOVE_ME[uint3(0, 0, 0)] = float4(evProcessedSum, w, avgEV, exposure); - _OutputTexture[uint2(0,0)] = float2(ConvertEV100ToExposure(exposure), exposure); - + _OutputTexture[uint2(0, 0)] = float2(ConvertEV100ToExposure(exposure), exposure); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset index 57616a47365..e184f221b67 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset @@ -100,6 +100,7 @@ MonoBehaviour: copyAlphaCS: {fileID: 7200000, guid: c2c7eb6611725264187721ef9df0354b, type: 3} nanKillerCS: {fileID: 7200000, guid: 83982f199acf927499576a99abc9bea9, type: 3} exposureCS: {fileID: 7200000, guid: 976d7bce54fae534fb9ec67e9c18570c, type: 3} + histogramExposureCS: {fileID: 7200000, guid: 222da48299136f34b8e3fb75ae9f8ac7, type: 3} applyExposureCS: {fileID: 7200000, guid: 1a6fea1dc099b984d8f2b27d504dc096, type: 3} uberPostCS: {fileID: 7200000, guid: f1bf52f7c71bffd4f91e6cd90d12a4f7, type: 3} lutBuilder3DCS: {fileID: 7200000, guid: 37f2b1b0ecd6f1c439e4c1b4f2fdb524, type: 3} From d25ccf96493d3e3f6e6d48a611d3801eba6cd289 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 27 Apr 2020 09:17:05 +0200 Subject: [PATCH 04/27] Commit as I need branch switching - Start debug modes --- .../Runtime/Debug/DebugDisplay.cs | 27 +++- .../Runtime/Debug/DebugDisplay.hlsl | 11 +- .../Runtime/Debug/DebugExposure.shader | 153 ++++++++++++++++++ .../Runtime/Debug/DebugExposure.shader.meta | 10 ++ .../Runtime/Debug/SceneExposureDebug.cs | 33 ++++ .../Runtime/Debug/SceneExposureDebug.cs.meta | 11 ++ .../PostProcessing/PostProcessSystem.cs | 5 + .../PostProcessing/Shaders/Exposure.compute | 29 +--- .../RenderPipeline/HDRenderPipeline.cs | 47 +++++- .../RenderPipeline/HDStringConstants.cs | 1 - .../RenderPipeline/RenderPipelineResources.cs | 2 + .../HDRenderPipelineResources.asset | 1 + 12 files changed, 301 insertions(+), 29 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 501cebc9b34..30c51fa85c0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -181,6 +181,8 @@ public class DebugData public MipMapDebugSettings mipMapDebugSettings = new MipMapDebugSettings(); /// Current color picker debug settings. public ColorPickerDebugSettings colorPickerDebugSettings = new ColorPickerDebugSettings(); + /// Current exposure debug settings. + public ExposureDebugSettings exposureDebugSettings = new ExposureDebugSettings(); // TODO_FCC: TODO Check where to put this. /// Current false color debug settings. public FalseColorDebugSettings falseColorDebugSettings = new FalseColorDebugSettings(); /// Current decals debug settings. @@ -218,6 +220,7 @@ public class DebugData internal int renderingFulscreenDebugModeEnumIndex; internal int terrainTextureEnumIndex; internal int colorPickerDebugModeEnumIndex; + internal int exposureDebugModeEnumIndex; internal int msaaSampleDebugModeEnumIndex; internal int debugCameraToFreezeEnumIndex; internal int volumeComponentEnumIndex; @@ -407,7 +410,7 @@ public bool IsDebugDisplayEnabled() /// True if any material debug display is enabled. public bool IsDebugMaterialDisplayEnabled() { - return data.materialDebugSettings.IsDebugDisplayEnabled(); + return data.materialDebugSettings.IsDebugDisplayEnabled(); } /// @@ -419,6 +422,15 @@ public bool IsDebugFullScreenEnabled() return data.fullScreenDebugMode != FullScreenDebugMode.None; } + /// + /// Returns true if any full screen exposure debug display is enabled. + /// + /// True if any full screen exposure debug display is enabled. + public bool IsDebugExposureModeEnabled() + { + return data.exposureDebugSettings.debugMode != ExposureDebugMode.None; + } + /// /// Returns true if material validation is enabled. /// @@ -1388,6 +1400,19 @@ void RegisterRenderingDebug() } }); + widgetList.AddRange(new[] +{ + new DebugUI.Container + { + displayName = "Exposure", + children = + { + new DebugUI.EnumField { displayName = "Debug Mode", getter = () => (int)data.exposureDebugSettings.debugMode, setter = value => data.exposureDebugSettings.debugMode = (ExposureDebugMode)value, autoEnum = typeof(ExposureDebugMode), getIndex = () => data.exposureDebugModeEnumIndex, setIndex = value => data.exposureDebugModeEnumIndex = value }, + } + } + }); + + widgetList.Add(new DebugUI.BoolField { displayName = "False Color Mode", getter = () => data.falseColorDebugSettings.falseColor, setter = value => data.falseColorDebugSettings.falseColor = value, onValueChanged = RefreshRenderingDebug }); if (data.falseColorDebugSettings.falseColor) { diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl index 9b5f009aa19..f7e7033b683 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl @@ -213,7 +213,7 @@ void DrawInteger(int intValue, float3 fontColor, uint2 currentUnormCoord, inout DrawInteger(intValue, fontColor, currentUnormCoord, fixedUnormCoord, color, 0, false); } -void DrawFloat(float floatValue, float3 fontColor, uint2 currentUnormCoord, inout uint2 fixedUnormCoord, inout float3 color) +void DrawFloatExplicitPrecision(float floatValue, float3 fontColor, uint2 currentUnormCoord, uint digitCount, inout uint2 fixedUnormCoord, inout float3 color) { if (IsNaN(floatValue)) { @@ -227,12 +227,17 @@ void DrawFloat(float floatValue, float3 fontColor, uint2 currentUnormCoord, inou bool forceNegativeSign = floatValue >= 0.0f ? false : true; DrawInteger(intValue, fontColor, currentUnormCoord, fixedUnormCoord, color, 0, forceNegativeSign); DrawCharacter('.', fontColor, currentUnormCoord, fixedUnormCoord, color); - int fracValue = int(frac(abs(floatValue)) * 1e6); // 6 digit - int leading0 = 6 - (int(log10(fracValue)) + 1); // Counting leading0 to add in front of the float + int fracValue = int(frac(abs(floatValue)) * pow(10, digitCount)); + int leading0 = digitCount - (int(log10(fracValue)) + 1); // Counting leading0 to add in front of the float DrawInteger(fracValue, fontColor, currentUnormCoord, fixedUnormCoord, color, leading0, false); } } +void DrawFloat(float floatValue, float3 fontColor, uint2 currentUnormCoord, inout uint2 fixedUnormCoord, inout float3 color) +{ + DrawFloatExplicitPrecision(floatValue, fontColor, currentUnormCoord, 6, fixedUnormCoord, color); +} + // Debug rendering is performed at the end of the frame (after post-processing). // Debug textures are never flipped upside-down automatically. Therefore, we must always flip manually. bool ShouldFlipDebugTexture() diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader new file mode 100644 index 00000000000..ba908889ffe --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -0,0 +1,153 @@ +Shader "Hidden/HDRP/DebugExposure" +{ + HLSLINCLUDE + +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" +#define DEBUG_DISPLAY +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" + + struct Attributes + { + uint vertexID : SV_VertexID; + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + float2 texcoord : TEXCOORD0; + }; + + Varyings Vert(Attributes input) + { + Varyings output; + output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID); + output.texcoord = GetNormalizedFullScreenTriangleTexCoord(input.vertexID); + + return output; + } + + float3 ToHeat(float value) + { + float3 r = value * 2.1f - float3(1.8f, 1.14f, 0.3f); + return 1.0f - r * r; + } + + // Returns true if it drew the location of the indicator. + void DrawHeatSideBar(float2 uv, float2 startSidebar, float2 endSidebar, float evValueRange, float3 indicatorColor, float2 sidebarSize, inout float3 sidebarColor) + { + float2 borderSize = 2 * _ScreenSize.zw; + uint indicatorHalfSize = 5; + + if (all(uv > startSidebar) && all(uv < endSidebar)) + { + float inRange = (uv.y - startSidebar.y) / (endSidebar.y - startSidebar.y); + evValueRange = clamp(evValueRange, 0.0f, 1.0f); + int distanceInPixels = abs(evValueRange - inRange) * sidebarSize.y * _ScreenSize.y; + if (distanceInPixels < indicatorHalfSize) + { + sidebarColor = indicatorColor; + } + else if (distanceInPixels < indicatorHalfSize + 1) + { + sidebarColor = 0.0f; + } + else + { + sidebarColor = ToHeat(inRange); + } + } + else if(all(uv > startSidebar - borderSize) && all(uv < endSidebar + borderSize)) + { + sidebarColor = 0.0f; + } + } + + float GetEVAtLocation(float2 uv) + { + float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); + float luma = Luminance(color / prevExposure); + + return ComputeEV100FromAvgLuminance(max(luma, 1e-4)); + } + + float3 Frag(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + float2 uv = input.texcoord.xy; + + float3 textColor = 0.0f; + + // TODO: Should they be in pixels? ASK UX! + float2 sidebarSize = float2(0.025, 0.7); + + float2 sidebarBottomLeft = float2(0.04, (1.0 - sidebarSize.y) * 0.5) * _RTHandleScale.xy; + float2 endPointSidebar = sidebarBottomLeft + sidebarSize * _RTHandleScale.xy; + + float3 outputColor = 0; + float ev = GetEVAtLocation(uv); + + float evInRange = (ev - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); + + if (ev < ParamExposureLimitMax && ev > ParamExposureLimitMin) + { + outputColor = ToHeat(evInRange); + } + else if (ev > ParamExposureLimitMax) // << TODO_FCC: Ask UX TODO what color scheme is good here. + { + outputColor = 1.0f; + } + else if (ev < ParamExposureLimitMin) + { + outputColor = 0.0f; + } + + // Get value at indicator + float2 indicatorUV = _MousePixelCoord.zw; + float indicatorEV = GetEVAtLocation(indicatorUV); + float indicatorEVRange = (indicatorEV - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); + + DrawHeatSideBar(uv, sidebarBottomLeft, endPointSidebar, indicatorEVRange, 0.66f, sidebarSize, outputColor); + + uint2 unormCoord = input.positionCS.xy; + + uint2 labelEVMinLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), 0); + uint2 textLocation = labelEVMinLoc; + DrawFloatExplicitPrecision(ParamExposureLimitMin, textColor, unormCoord, 1, textLocation, outputColor.rgb); + uint2 labelEVMaxLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), sidebarSize.y * 0.98 * _ScreenSize.y); + textLocation = labelEVMaxLoc; + DrawFloatExplicitPrecision(ParamExposureLimitMax, textColor, unormCoord, 1, textLocation, outputColor.rgb); + + int displayTextOffsetX = 1.5 * DEBUG_FONT_TEXT_WIDTH; + textLocation = uint2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); + DrawFloatExplicitPrecision(indicatorEV, textColor, unormCoord, 1, textLocation, outputColor.rgb); + + return outputColor; + } + + ENDHLSL + + SubShader + { + Tags{ "RenderPipeline" = "HDRenderPipeline" } + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + + HLSLPROGRAM + #pragma enable_d3d11_debug_symbols // TODO_FCC TODO : REMOVE + #pragma target 4.5 + #pragma only_renderers d3d11 playstation xboxone vulkan metal switch + + #pragma vertex Vert + #pragma fragment Frag + + ENDHLSL + } + + } + Fallback Off +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader.meta new file mode 100644 index 00000000000..4383c002901 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0ef322534f047a34c96d29419d56d17a +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs new file mode 100644 index 00000000000..8cdedfe9111 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs @@ -0,0 +1,33 @@ +using System; + +namespace UnityEngine.Rendering.HighDefinition +{ + /// + /// Color Picker Debug Mode. + /// + [GenerateHLSL] + public enum ExposureDebugMode + { + /// No exposure debug. + None, + /// TODO_FCC ADD TODO. + SceneEV100Values, + /// TODO_FCC ADD TODO + HistogramView, + /// TODO_FCC Visualize metering + Metering, + + } + + /// + /// Exposure debug settings. + /// + [Serializable] + public class ExposureDebugSettings + { + /// + /// Exposure picker mode. + /// + public ExposureDebugMode debugMode = ExposureDebugMode.None; + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta new file mode 100644 index 00000000000..def02b50d9e --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2b7dd93929f3044ca05cd5608ff49c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index e1d8a1aae60..9746b8ba4ca 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -775,6 +775,11 @@ public RTHandle GetPreviousExposureTexture(HDCamera camera) return rt ?? m_EmptyExposureTexture; } + public ComputeBuffer GetHistogramBuffer() + { + return m_HistogramBuffer; + } + void DoFixedExposure(CommandBuffer cmd, HDCamera camera) { var cs = m_Resources.shaders.exposureCS; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute index 7e0c2583ed8..5b0e781a747 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute @@ -11,10 +11,9 @@ TEXTURE2D(_ExposureCurveTexture); TEXTURE2D(_InputTexture); -#pragma enable_d3d11_debug_symbols - #define PREPASS_TEX_SIZE 1024.0 #define PREPASS_TEX_HALF_SIZE 512.0 +#pragma enable_d3d11_debug_symbols // // Fixed exposure @@ -41,12 +40,13 @@ void KManualCameraExposure(uint2 dispatchThreadId : SV_DispatchThreadID) } +// TODO_FCC: REMOVE THIS. uint GetHistogramBinLocation(float value) { float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * 0.0333333333f + 0.33333333333; return uint(saturate(scaledLogLuma) * (128 - 1)); } - +// TODO_FCC: REMOVE THIS. float BinLocationToLogLuma(uint binIdx) { return (binIdx * rcp(float(128 - 1)) - 0.33333333333) / 0.0333333333f; @@ -66,30 +66,13 @@ void KPrePass(uint2 dispatchThreadId : SV_DispatchThreadID) PositionInputs posInputs = GetPositionInput(float2(dispatchThreadId), rcp(PREPASS_TEX_SIZE), uint2(8u, 8u)); float2 uv = ClampAndScaleUVForBilinear(posInputs.positionNDC); - float luma; - - UNITY_BRANCH - switch (ParamSourceBuffer) - { - case 1u: - { - // Color buffer - float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; - luma = Luminance(color / prevExposure); - break; - } - default: - { - // Lighting buffer - luma = 1.0; - break; - } - } + float luma = SampleLuminance(uv); float weight = WeightSample(dispatchThreadId, PREPASS_TEX_SIZE.xx); + uint bin = GetHistogramBinLocation(luma); float value = BinLocationToLogLuma(bin); + float logLuma = ComputeEV100FromAvgLuminance(max(luma, 1e-4)); _OutputTexture[posInputs.positionSS] = float2(value, weight); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 42cef9ae8be..98d77bdf545 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -145,6 +145,7 @@ internal static Volume GetOrCreateDefaultVolume() Material m_DebugFullScreen; MaterialPropertyBlock m_DebugFullScreenPropertyBlock = new MaterialPropertyBlock(); Material m_DebugColorPicker; + Material m_DebugExposure; Material m_ErrorMaterial; Material m_Blit; @@ -811,6 +812,7 @@ void InitializeDebugMaterials() m_DebugDisplayLatlong = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugDisplayLatlongPS); m_DebugFullScreen = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugFullScreenPS); m_DebugColorPicker = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugColorPickerPS); + m_DebugExposure = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugExposurePS); m_Blit = CoreUtils.CreateEngineMaterial(defaultResources.shaders.blitPS); m_ErrorMaterial = CoreUtils.CreateEngineMaterial("Hidden/InternalErrorShader"); @@ -895,6 +897,7 @@ protected override void Dispose(bool disposing) CoreUtils.Destroy(m_DebugDisplayLatlong); CoreUtils.Destroy(m_DebugFullScreen); CoreUtils.Destroy(m_DebugColorPicker); + CoreUtils.Destroy(m_DebugExposure); CoreUtils.Destroy(m_Blit); CoreUtils.Destroy(m_BlitTexArray); CoreUtils.Destroy(m_BlitTexArraySingleSlice); @@ -4171,7 +4174,8 @@ unsafe void ApplyDebugDisplaySettings(HDCamera hdCamera, CommandBuffer cmd) cmd.SetGlobalTexture(HDShaderIDs._DebugMatCapTexture, defaultResources.textures.matcapTex); if (debugDisplayEnabledOrSceneLightingDisabled || - m_CurrentDebugDisplaySettings.data.colorPickerDebugSettings.colorPickerMode != ColorPickerDebugMode.None) + m_CurrentDebugDisplaySettings.data.colorPickerDebugSettings.colorPickerMode != ColorPickerDebugMode.None || + m_CurrentDebugDisplaySettings.IsDebugExposureModeEnabled()) { // This is for texture streaming m_CurrentDebugDisplaySettings.UpdateMaterials(); @@ -4260,6 +4264,11 @@ void PushColorPickerDebugTexture(CommandBuffer cmd, HDCamera hdCamera, RTHandle } } + bool NeedExposureDebugMode(DebugDisplaySettings debugSettings) + { + return debugSettings.data.exposureDebugSettings.debugMode != ExposureDebugMode.None; + } + bool NeedsFullScreenDebugMode() { bool fullScreenDebugEnabled = m_CurrentDebugDisplaySettings.data.fullScreenDebugMode != FullScreenDebugMode.None; @@ -4323,6 +4332,10 @@ struct DebugParameters // Color picker public bool colorPickerEnabled; public Material colorPickerMaterial; + + // Exposure + public bool exposureDebugEnabled; + public Material debugExposureMaterial; } DebugParameters PrepareDebugParameters(HDCamera hdCamera, HDUtils.PackedMipChainInfo depthMipInfo) @@ -4347,6 +4360,9 @@ DebugParameters PrepareDebugParameters(HDCamera hdCamera, HDUtils.PackedMipChain parameters.colorPickerEnabled = NeedColorPickerDebug(parameters.debugDisplaySettings); parameters.colorPickerMaterial = m_DebugColorPicker; + parameters.exposureDebugEnabled = NeedExposureDebugMode(parameters.debugDisplaySettings); + parameters.debugExposureMaterial = m_DebugExposure; + return parameters; } @@ -4394,6 +4410,29 @@ static void ResolveColorPickerDebug(in DebugParameters parameters, HDUtils.DrawFullScreen(cmd, parameters.colorPickerMaterial, output); } + static void RenderExposureDebug(in DebugParameters parameters, + RTHandle inputColorBuffer, + RTHandle prevExposure, + RTHandle output, + ComputeBuffer histogramBuffer, + CommandBuffer cmd) + { + + //parameters.exposureMaterial.set + // Grab exposure parameters + var exposureSettings = parameters.hdCamera.volumeStack.GetComponent(); + + Vector4 exposureParams = new Vector4(exposureSettings.compensation.value + parameters.debugDisplaySettings.data.lightingDebugSettings.debugExposure, exposureSettings.limitMin.value, + exposureSettings.limitMax.value, 0f); + + parameters.debugExposureMaterial.SetVector(HDShaderIDs._ExposureParams, exposureParams); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._MousePixelCoord, HDUtils.GetMouseCoordinates(parameters.hdCamera)); + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._SourceTexture, inputColorBuffer); + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._PreviousExposureTexture, prevExposure); + + HDUtils.DrawFullScreen(cmd, parameters.debugExposureMaterial, output, null, 0); + } + static void RenderSkyReflectionOverlay(in DebugParameters debugParameters, CommandBuffer cmd, MaterialPropertyBlock mpb, ref float x, ref float y, float overlaySize) { var lightingDebug = debugParameters.debugDisplaySettings.data.lightingDebugSettings; @@ -4436,6 +4475,12 @@ void RenderDebug(HDCamera hdCamera, CommandBuffer cmd, CullingResults cullResult PushColorPickerDebugTexture(cmd, hdCamera, m_IntermediateAfterPostProcessBuffer); } + // TODO_FCC: Should this be inside the fullscreen debug ? Probably... + if (debugParams.exposureDebugEnabled) + { + RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); + } + // First resolve color picker if (debugParams.colorPickerEnabled) ResolveColorPickerDebug(debugParams, m_DebugColorPickerBuffer, m_IntermediateAfterPostProcessBuffer, cmd); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index d542e9bc211..150893aa85b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -598,7 +598,6 @@ static class HDShaderIDs public static readonly int _ExposureParams = Shader.PropertyToID("_ExposureParams"); public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); public static readonly int _HistogramBuffer = Shader.PropertyToID("_HistogramBuffer"); - public static readonly int _TODO_REMOVE_ME = Shader.PropertyToID("_TODO_REMOVE_ME"); public static readonly int _AdaptationParams = Shader.PropertyToID("_AdaptationParams"); public static readonly int _ExposureCurveTexture = Shader.PropertyToID("_ExposureCurveTexture"); public static readonly int _ExposureWeightMask = Shader.PropertyToID("_ExposureWeightMask"); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs index 52d860f21e8..61aeae5305a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -25,6 +25,8 @@ public sealed class ShaderResources public Shader debugFullScreenPS; [Reload("Runtime/Debug/DebugColorPicker.Shader")] public Shader debugColorPickerPS; + [Reload("Runtime/Debug/DebugExposure.Shader")] + public Shader debugExposurePS; [Reload("Runtime/Debug/DebugLightVolumes.Shader")] public Shader debugLightVolumePS; [Reload("Runtime/Debug/DebugLightVolumes.compute")] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset index e184f221b67..b32d219933d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset @@ -20,6 +20,7 @@ MonoBehaviour: debugViewTilesPS: {fileID: 4800000, guid: c7c2bd17b06ceb4468e14081aaf1b96f, type: 3} debugFullScreenPS: {fileID: 4800000, guid: e874aca2df8300a488258738c31f85cf, type: 3} debugColorPickerPS: {fileID: 4800000, guid: 8137b807709e178498f22ed710864bb0, type: 3} + debugExposurePS: {fileID: 4800000, guid: 0ef322534f047a34c96d29419d56d17a, type: 3} debugLightVolumePS: {fileID: 4800000, guid: 8e706c0e71fcec34a8f5c9713e5e2943, type: 3} debugLightVolumeCS: {fileID: 7200000, guid: f5d5d21faef5cf445ac2c5d8ff9c4184, type: 3} debugBlitQuad: {fileID: 4800000, guid: cf5ca5b6ef18b3f429ed707ee9ceac9f, type: 3} From 64cad47ff4d9806979f62e38548c44c0232944cb Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Apr 2020 15:21:56 +0200 Subject: [PATCH 05/27] Add a bunch of debug mode and start of histogram --- .../Runtime/Debug/DebugExposure.shader | 173 ++++++++++++++++-- .../Runtime/Debug/SceneExposureDebug.cs | 2 +- .../Shaders/HistogramExposure.compute | 31 +--- .../Shaders/HistogramExposureCommon.hlsl | 29 +++ .../Shaders/HistogramExposureCommon.hlsl.meta | 10 + .../RenderPipeline/HDRenderPipeline.cs | 19 +- 6 files changed, 215 insertions(+), 49 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index ba908889ffe..1f3871c4429 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -2,9 +2,20 @@ Shader "Hidden/HDRP/DebugExposure" { HLSLINCLUDE -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" -#define DEBUG_DISPLAY -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl" + #define DEBUG_DISPLAY + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" + + #pragma vertex Vert + + #pragma target 4.5 + #pragma only_renderers d3d11 playstation xboxone vulkan metal switch + + //TEXTURE2D(_ExposureTexture); + + // REMOVE +#pragma enable_d3d11_debug_symbols struct Attributes { @@ -62,6 +73,91 @@ Shader "Hidden/HDRP/DebugExposure" } } + float GetHistogramValue(float coord, out bool isEdge) + { + float barSize = _ScreenSize.x / HISTOGRAM_BINS; + float bin = coord / barSize; + + float locWithinBin = barSize * frac(bin); + + isEdge = locWithinBin < 1 || locWithinBin > (barSize - 1); + return UnpackWeight(_HistogramBuffer[(uint)(bin)]); + } + + void DrawHistogramIndicatorBar(uint coord, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) + { + float halfWidthInScreen = widthNDC * _ScreenSize.x; + float minScreenPos = (uvXLocation - widthNDC * 0.5) * _ScreenSize.x; + float maxScreenPos = (uvXLocation + widthNDC * 0.5) * _ScreenSize.x; + + if (coord > minScreenPos && coord < maxScreenPos) + { + outColor = color; + } + } + + void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, inout float3 outColor) + { + float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; + + if (uv.y > frameHeight) return; + + // ---- Draw General frame ---- + if (uv.x < borderSize.x || uv.x >(1.0f - borderSize.x)) outColor = 0.0; + else if (uv.y > frameHeight - borderSize.y || uv.y < borderSize.y) outColor = 0.0; + else + outColor = lerp(outColor, backgroundColor, alpha); + + // ---- Draw Buckets frame ---- + float maxValue = 0; + for (int i = 0; i <= HISTOGRAM_BINS; ++i) + { + float histogramVal = UnpackWeight(_HistogramBuffer[i]); + maxValue = max(histogramVal, maxValue); + } + + bool isEdgeOfBin = false; + float val = GetHistogramValue(unormCoord.x, isEdgeOfBin); + val /= maxValue; + + val *= (frameHeight * 0.9); + if (uv.y < val) + { + isEdgeOfBin = isEdgeOfBin || (uv.y > val - _ScreenSize.w); + + outColor.rgb = float3(1.0f, 1.0f, 1.0f); + if (isEdgeOfBin) outColor.rgb = 0; + } + + // ---- Draw indicators ---- + // void DrawHistogramIndicatorBar(uint coord, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) + float currExposure = _ExposureTexture[int2(0, 0)].y; + float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); + DrawHistogramIndicatorBar(unormCoord.xy, evInRange, 0.002f, float3(0, 0, 1), outColor); + + + // ---- Draw labels ---- + + // Number of labels + int labelCount = 12; + float oneOverLabelCount = rcp(labelCount); + float labelDeltaScreenSpace = _ScreenSize.x * oneOverLabelCount; + + int minLabelLocationX = DEBUG_FONT_TEXT_WIDTH * 0.25; + int maxLabelLocationX = _ScreenSize.x - (DEBUG_FONT_TEXT_WIDTH * 3); + + int labelLocationY = DEBUG_FONT_TEXT_WIDTH * 0.15; + + [unroll] + for (int i = 0; i <= labelCount; ++i) + { + float t = oneOverLabelCount * i; + float labelValue = lerp(ParamExposureLimitMin, ParamExposureLimitMax, t); + uint2 labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY); + DrawFloatExplicitPrecision(labelValue, float3(1.0f, 0, 0), unormCoord, 1, labelLoc, outColor.rgb); + } + } + float GetEVAtLocation(float2 uv) { float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; @@ -71,7 +167,17 @@ Shader "Hidden/HDRP/DebugExposure" return ComputeEV100FromAvgLuminance(max(luma, 1e-4)); } - float3 Frag(Varyings input) : SV_Target + float3 FragMetering(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + float2 uv = input.texcoord.xy; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); + + return color * weight;// lerp(, color, 0.025f); + } + + float3 FragSceneEV100(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float2 uv = input.texcoord.xy; @@ -109,22 +215,41 @@ Shader "Hidden/HDRP/DebugExposure" DrawHeatSideBar(uv, sidebarBottomLeft, endPointSidebar, indicatorEVRange, 0.66f, sidebarSize, outputColor); - uint2 unormCoord = input.positionCS.xy; + int2 unormCoord = input.positionCS.xy; - uint2 labelEVMinLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), 0); - uint2 textLocation = labelEVMinLoc; + int2 labelEVMinLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), 0); + int2 textLocation = labelEVMinLoc; DrawFloatExplicitPrecision(ParamExposureLimitMin, textColor, unormCoord, 1, textLocation, outputColor.rgb); - uint2 labelEVMaxLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), sidebarSize.y * 0.98 * _ScreenSize.y); + int2 labelEVMaxLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), sidebarSize.y * 0.98 * _ScreenSize.y); textLocation = labelEVMaxLoc; DrawFloatExplicitPrecision(ParamExposureLimitMax, textColor, unormCoord, 1, textLocation, outputColor.rgb); - int displayTextOffsetX = 1.5 * DEBUG_FONT_TEXT_WIDTH; - textLocation = uint2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); + int displayTextOffsetX = DEBUG_FONT_TEXT_WIDTH; + textLocation = int2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); DrawFloatExplicitPrecision(indicatorEV, textColor, unormCoord, 1, textLocation, outputColor.rgb); + return outputColor; } + + + float3 FragHistogram(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + float2 uv = input.texcoord.xy; + + + + float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); + + float3 outputColor = color; + DrawHistogramFrame(uv, input.positionCS.xy, 0.2 * _RTHandleScale.y, ToHeat(uv.x), 0.1f, outputColor); + + return outputColor;// lerp(, color, 0.025f); + } + ENDHLSL SubShader @@ -138,13 +263,31 @@ Shader "Hidden/HDRP/DebugExposure" Cull Off HLSLPROGRAM - #pragma enable_d3d11_debug_symbols // TODO_FCC TODO : REMOVE - #pragma target 4.5 - #pragma only_renderers d3d11 playstation xboxone vulkan metal switch + #pragma fragment FragSceneEV100 + ENDHLSL + } + + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + + HLSLPROGRAM + #pragma fragment FragMetering + ENDHLSL + } - #pragma vertex Vert - #pragma fragment Frag + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + HLSLPROGRAM + #pragma fragment FragHistogram ENDHLSL } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs index 8cdedfe9111..63a36782da7 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs @@ -15,7 +15,7 @@ public enum ExposureDebugMode /// TODO_FCC ADD TODO HistogramView, /// TODO_FCC Visualize metering - Metering, + MeteringWeighted, } diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index 01edbe68955..b29277bf9fe 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -1,4 +1,5 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl" #pragma enable_d3d11_debug_symbols @@ -16,23 +17,9 @@ #pragma kernel KHistogramGen GEN_PASS #pragma kernel KHistogramReduce REDUCE_PASS - -#define _HistogramRangeScale _HistogramExposureParams.x -#define _HistogramRangeBias _HistogramExposureParams.y -#define _HistogramMinPercentage _HistogramExposureParams.z -#define _HistogramMaxPercentage _HistogramExposureParams.w - - -#define HISTOGRAM_BINS 128 // IMPORTANT: If this number is changed, the code needs adapting, I tried to add relevant comments to indicate where. #define GROUP_SIZE_X 16 #define GROUP_SIZE_Y 8 -#ifdef GEN_PASS -RWStructuredBuffer _HistogramBuffer; -#else -StructuredBuffer _HistogramBuffer; -#endif - // Because atomics are only on uint and we need a weighted value, we need to convert. // If we multiply the weight by 2048, we get somewhat ok precision and we support up to @@ -42,22 +29,6 @@ uint PackWeight(float weight) return uint(weight * 2048); } -float UnpackWeight(uint val) -{ - return val * rcp(2048.0f); -} - -uint GetHistogramBinLocation(float value) -{ - float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * _HistogramRangeScale + _HistogramRangeBias; - return uint(saturate(scaledLogLuma) * (HISTOGRAM_BINS - 1)); -} - -float BinLocationToEV(uint binIdx) -{ - return (binIdx * rcp(float(HISTOGRAM_BINS - 1)) - _HistogramRangeBias) / _HistogramRangeScale; -} - groupshared uint gs_localHistogram[HISTOGRAM_BINS]; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl new file mode 100644 index 00000000000..4a448ee69da --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl @@ -0,0 +1,29 @@ + +#define HISTOGRAM_BINS 128 // IMPORTANT: If this number is changed, the code needs adapting, I tried to add relevant comments to indicate where. + +#define _HistogramRangeScale _HistogramExposureParams.x +#define _HistogramRangeBias _HistogramExposureParams.y +#define _HistogramMinPercentage _HistogramExposureParams.z +#define _HistogramMaxPercentage _HistogramExposureParams.w + +#ifdef GEN_PASS +RWStructuredBuffer _HistogramBuffer; +#else +StructuredBuffer _HistogramBuffer; +#endif + +float UnpackWeight(uint val) +{ + return val * rcp(2048.0f); +} + +uint GetHistogramBinLocation(float value) +{ + float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * _HistogramRangeScale + _HistogramRangeBias; + return uint(saturate(scaledLogLuma) * (HISTOGRAM_BINS - 1)); +} + +float BinLocationToEV(uint binIdx) +{ + return (binIdx * rcp(float(HISTOGRAM_BINS - 1)) - _HistogramRangeBias) / _HistogramRangeScale; +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl.meta new file mode 100644 index 00000000000..11a0b6748c6 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8b66a6c34796d04498345e5530eb228c +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 98d77bdf545..e01b5d1dd00 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4412,6 +4412,7 @@ static void ResolveColorPickerDebug(in DebugParameters parameters, static void RenderExposureDebug(in DebugParameters parameters, RTHandle inputColorBuffer, + RTHandle currentExposure, RTHandle prevExposure, RTHandle output, ComputeBuffer histogramBuffer, @@ -4425,12 +4426,24 @@ static void RenderExposureDebug(in DebugParameters parameters, Vector4 exposureParams = new Vector4(exposureSettings.compensation.value + parameters.debugDisplaySettings.data.lightingDebugSettings.debugExposure, exposureSettings.limitMin.value, exposureSettings.limitMax.value, 0f); + Vector4 exposureVariants = new Vector4(1.0f, (int)exposureSettings.meteringMode.value, (int)exposureSettings.adaptationMode.value, 0.0f); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._Variants, exposureVariants); parameters.debugExposureMaterial.SetVector(HDShaderIDs._ExposureParams, exposureParams); parameters.debugExposureMaterial.SetVector(HDShaderIDs._MousePixelCoord, HDUtils.GetMouseCoordinates(parameters.hdCamera)); parameters.debugExposureMaterial.SetTexture(HDShaderIDs._SourceTexture, inputColorBuffer); parameters.debugExposureMaterial.SetTexture(HDShaderIDs._PreviousExposureTexture, prevExposure); - - HDUtils.DrawFullScreen(cmd, parameters.debugExposureMaterial, output, null, 0); + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._ExposureTexture, currentExposure); + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._ExposureWeightMask, exposureSettings.weightTextureMask.value); + parameters.debugExposureMaterial.SetBuffer(HDShaderIDs._HistogramBuffer, histogramBuffer); + + + int passIndex = 0; + if (parameters.debugDisplaySettings.data.exposureDebugSettings.debugMode == ExposureDebugMode.MeteringWeighted) + passIndex = 1; + if (parameters.debugDisplaySettings.data.exposureDebugSettings.debugMode == ExposureDebugMode.HistogramView) + passIndex = 2; + + HDUtils.DrawFullScreen(cmd, parameters.debugExposureMaterial, output, null, passIndex); } static void RenderSkyReflectionOverlay(in DebugParameters debugParameters, CommandBuffer cmd, MaterialPropertyBlock mpb, ref float x, ref float y, float overlaySize) @@ -4478,7 +4491,7 @@ void RenderDebug(HDCamera hdCamera, CommandBuffer cmd, CullingResults cullResult // TODO_FCC: Should this be inside the fullscreen debug ? Probably... if (debugParams.exposureDebugEnabled) { - RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); + RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); } // First resolve color picker From f2b71e010272459c1f51486dae0bd918f0292bd1 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Apr 2020 20:22:13 +0200 Subject: [PATCH 06/27] Delimiters indicator with bars --- .../Runtime/Debug/DebugExposure.shader | 134 ++++++++++++++---- .../PostProcessing/Components/Exposure.cs | 3 +- .../Shaders/ExposureCommon.hlsl | 1 + .../Shaders/HistogramExposure.compute | 6 +- .../Shaders/HistogramExposureCommon.hlsl | 12 +- .../RenderPipeline/HDRenderPipeline.cs | 7 + 6 files changed, 128 insertions(+), 35 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 1f3871c4429..599f36210cd 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -12,8 +12,6 @@ Shader "Hidden/HDRP/DebugExposure" #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch - //TEXTURE2D(_ExposureTexture); - // REMOVE #pragma enable_d3d11_debug_symbols @@ -43,10 +41,19 @@ Shader "Hidden/HDRP/DebugExposure" return 1.0f - r * r; } + float GetEVAtLocation(float2 uv) + { + float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); + float luma = Luminance(color / prevExposure); + + return ComputeEV100FromAvgLuminance(max(luma, 1e-4)); + } + // Returns true if it drew the location of the indicator. void DrawHeatSideBar(float2 uv, float2 startSidebar, float2 endSidebar, float evValueRange, float3 indicatorColor, float2 sidebarSize, inout float3 sidebarColor) { - float2 borderSize = 2 * _ScreenSize.zw; + float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; uint indicatorHalfSize = 5; if (all(uv > startSidebar) && all(uv < endSidebar)) @@ -84,6 +91,53 @@ Shader "Hidden/HDRP/DebugExposure" return UnpackWeight(_HistogramBuffer[(uint)(bin)]); } + float ComputePercentile(float2 uv, float histSum, out float minPercentileBin, out float maxPercentileBin) + { + float sumBelowValue = 0.0f; + float sumForMin = 0.0f; + float sumForMax = 0.0f; + + minPercentileBin = -1; + maxPercentileBin = -1; + + float ev = GetEVAtLocation(uv); + + for (int i = 0; i < HISTOGRAM_BINS; ++i) + { + float evAtBin = BinLocationToEV(i); + float evAtNextBin = BinLocationToEV(i+1); + + float histVal = UnpackWeight(_HistogramBuffer[i]); + + if (ev >= evAtBin) + { + sumBelowValue += histVal; + } + + //TODO: This could be more precise, now it locks to bin location + if (minPercentileBin < 0) + { + sumForMin += histVal; + if (sumForMin / histSum >= _HistogramMinPercentile) + { + + minPercentileBin = i; + } + } + + if (maxPercentileBin < 0) + { + sumForMax += histVal; + if (sumForMax / histSum >= _HistogramMaxPercentile) + { + maxPercentileBin = i; + } + } + } + + return sumBelowValue / histSum; + } + void DrawHistogramIndicatorBar(uint coord, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) { float halfWidthInScreen = widthNDC * _ScreenSize.x; @@ -96,29 +150,33 @@ Shader "Hidden/HDRP/DebugExposure" } } - void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, inout float3 outColor) + void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, float maxHist, float minPercentLoc, float maxPercentLoc, inout float3 outColor) { float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; if (uv.y > frameHeight) return; // ---- Draw General frame ---- - if (uv.x < borderSize.x || uv.x >(1.0f - borderSize.x)) outColor = 0.0; - else if (uv.y > frameHeight - borderSize.y || uv.y < borderSize.y) outColor = 0.0; + if (uv.x < borderSize.x || uv.x >(1.0f - borderSize.x)) + { + outColor = 0.0; + return; + } + else if (uv.y > frameHeight - borderSize.y || uv.y < borderSize.y) + { + outColor = 0.0; + return; + } else - outColor = lerp(outColor, backgroundColor, alpha); - - // ---- Draw Buckets frame ---- - float maxValue = 0; - for (int i = 0; i <= HISTOGRAM_BINS; ++i) { - float histogramVal = UnpackWeight(_HistogramBuffer[i]); - maxValue = max(histogramVal, maxValue); + outColor = lerp(outColor, backgroundColor, alpha); } + // ---- Draw Buckets frame ---- + bool isEdgeOfBin = false; float val = GetHistogramValue(unormCoord.x, isEdgeOfBin); - val /= maxValue; + val /= maxHist; val *= (frameHeight * 0.9); if (uv.y < val) @@ -130,11 +188,14 @@ Shader "Hidden/HDRP/DebugExposure" } // ---- Draw indicators ---- - // void DrawHistogramIndicatorBar(uint coord, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) float currExposure = _ExposureTexture[int2(0, 0)].y; float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - DrawHistogramIndicatorBar(unormCoord.xy, evInRange, 0.002f, float3(0, 0, 1), outColor); + DrawHistogramIndicatorBar(unormCoord.xy, evInRange, 0.002f, 0.05, outColor); + // Find location for percentiles bars. + + DrawHistogramIndicatorBar(unormCoord.xy, minPercentLoc, 0.002f, float3(0, 0, 1), outColor); + DrawHistogramIndicatorBar(unormCoord.xy, maxPercentLoc, 0.002f, float3(1, 0, 0), outColor); // ---- Draw labels ---- @@ -154,18 +215,11 @@ Shader "Hidden/HDRP/DebugExposure" float t = oneOverLabelCount * i; float labelValue = lerp(ParamExposureLimitMin, ParamExposureLimitMax, t); uint2 labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY); - DrawFloatExplicitPrecision(labelValue, float3(1.0f, 0, 0), unormCoord, 1, labelLoc, outColor.rgb); + DrawFloatExplicitPrecision(labelValue, float3(1.0f, 0.0f, 0.0f), unormCoord, 1, labelLoc, outColor.rgb); } } - float GetEVAtLocation(float2 uv) - { - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; - float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); - float luma = Luminance(color / prevExposure); - return ComputeEV100FromAvgLuminance(max(luma, 1e-4)); - } float3 FragMetering(Varyings input) : SV_Target { @@ -239,13 +293,39 @@ Shader "Hidden/HDRP/DebugExposure" UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float2 uv = input.texcoord.xy; - - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); float3 outputColor = color; - DrawHistogramFrame(uv, input.positionCS.xy, 0.2 * _RTHandleScale.y, ToHeat(uv.x), 0.1f, outputColor); + + // Get some overall info from the histogram + float maxValue = 0; + float sum = 0; + for (int i = 0; i < HISTOGRAM_BINS; ++i) + { + float histogramVal = UnpackWeight(_HistogramBuffer[i]); + maxValue = max(histogramVal, maxValue); + sum += histogramVal; + } + + float minPercentileBin = 0; + float maxPercentileBin = 0; + float percentile = ComputePercentile(uv, sum, minPercentileBin, maxPercentileBin); + + if (percentile < _HistogramMinPercentile) + { + outputColor = (input.positionCS.x + input.positionCS.y) % 2 == 0 ? float3(0.0f, 0.0f, 1.0) : color*0.33; + } + if (percentile > _HistogramMaxPercentile) + { + outputColor = (input.positionCS.x + input.positionCS.y) % 2 == 0 ? float3(1.0, 0.0f, 0.0f) : color * 0.33; + } + + float histFrameHeight = 0.2 * _RTHandleScale.y; + float minPercentileLoc = minPercentileBin / (HISTOGRAM_BINS-1); + float maxPercentileLoc = maxPercentileBin / (HISTOGRAM_BINS-1); + DrawHistogramFrame(uv, input.positionCS.xy, histFrameHeight, ToHeat(uv.x), 0.1f, maxValue, minPercentileLoc, maxPercentileLoc, outputColor); + return outputColor;// lerp(, color, 0.025f); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs index a2aafe0a720..5c4e563a776 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs @@ -91,6 +91,7 @@ public sealed class Exposure : VolumeComponent, IPostProcessComponent [Tooltip("Sets the texture mask to be used to weight the pixels in the buffer for the sake of computing exposure.")] public NoInterpTextureParameter weightTextureMask = new NoInterpTextureParameter(null); + // TODO_FCC TODO: DO BEFORE PR. Better name and doc here. /// /// These values are the lower and upper percentages of the histogram that will be used to @@ -98,7 +99,7 @@ public sealed class Exposure : VolumeComponent, IPostProcessComponent /// contribute to the average luminance. /// [Tooltip("Sets the range of values (in terms of percentages) of the histogram that are accepted while finding a stable average exposure. Anything outside the value is discarded.")] - public FloatRangeParameter histogramPercentages = new FloatRangeParameter(new Vector2(50.0f, 90.0f), 0.001f, 100.0f); + public FloatRangeParameter histogramPercentages = new FloatRangeParameter(new Vector2(50.0f, 90.0f), 0.0f, 100.0f); /// /// Tells if the effect needs to be rendered or not. diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl index a91c2093fe4..27143114442 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl @@ -3,6 +3,7 @@ #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/PhysicalCamera.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + TEXTURE2D(_ExposureWeightMask); TEXTURE2D_X(_SourceTexture); TEXTURE2D(_PreviousExposureTexture); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index b29277bf9fe..e525f76475a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -136,11 +136,11 @@ void ProcessBin(uint binIndex, inout float2 extremesSums, inout float evSum, ino float histVal = gs_values[binIndex]; float binEV = BinLocationToEV(binIndex); - // Low values + // Shadows float off = min(extremesSums.x, histVal); extremesSums -= off; histVal -= off; - // High values + // Highlights histVal = min(extremesSums.y, histVal); extremesSums.y -= histVal; @@ -158,7 +158,7 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) float sum = ComputeTotalSum(threadID, histogramVal); - float2 extremesSums = float2(_HistogramMinPercentage, _HistogramMaxPercentage) * sum; + float2 extremesSums = float2(_HistogramMinPercentile, _HistogramMaxPercentile) * sum; // TODO: This can probably done more efficiently. Also verify that all but the first wave // actually skip this or if we need to enforce it somehow. diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl index 4a448ee69da..5a046251fa4 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl @@ -3,8 +3,8 @@ #define _HistogramRangeScale _HistogramExposureParams.x #define _HistogramRangeBias _HistogramExposureParams.y -#define _HistogramMinPercentage _HistogramExposureParams.z -#define _HistogramMaxPercentage _HistogramExposureParams.w +#define _HistogramMinPercentile _HistogramExposureParams.z +#define _HistogramMaxPercentile _HistogramExposureParams.w #ifdef GEN_PASS RWStructuredBuffer _HistogramBuffer; @@ -17,10 +17,14 @@ float UnpackWeight(uint val) return val * rcp(2048.0f); } +float GetFractionWithinHistogram(float value) +{ + return ComputeEV100FromAvgLuminance(value) * _HistogramRangeScale + _HistogramRangeBias; +} + uint GetHistogramBinLocation(float value) { - float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * _HistogramRangeScale + _HistogramRangeBias; - return uint(saturate(scaledLogLuma) * (HISTOGRAM_BINS - 1)); + return uint(saturate(GetFractionWithinHistogram(value)) * (HISTOGRAM_BINS - 1)); } float BinLocationToEV(uint binIdx) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index e01b5d1dd00..2f8b96fcec7 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4427,6 +4427,13 @@ static void RenderExposureDebug(in DebugParameters parameters, exposureSettings.limitMax.value, 0f); Vector4 exposureVariants = new Vector4(1.0f, (int)exposureSettings.meteringMode.value, (int)exposureSettings.adaptationMode.value, 0.0f); + Vector2 histogramFraction = exposureSettings.histogramPercentages.value / 100.0f; + float evRange = exposureSettings.limitMax.value - exposureSettings.limitMin.value; + float histScale = 1.0f / Mathf.Max(1e-5f, evRange); + float histBias = -exposureSettings.limitMin.value * histScale; + Vector4 histogramParams = new Vector4(histScale, histBias, histogramFraction.x, histogramFraction.y); + + parameters.debugExposureMaterial.SetVector(HDShaderIDs._HistogramExposureParams, histogramParams); parameters.debugExposureMaterial.SetVector(HDShaderIDs._Variants, exposureVariants); parameters.debugExposureMaterial.SetVector(HDShaderIDs._ExposureParams, exposureParams); parameters.debugExposureMaterial.SetVector(HDShaderIDs._MousePixelCoord, HDUtils.GetMouseCoordinates(parameters.hdCamera)); From 86be36d5bb65beb47c2357618bd06cc3e24e0e57 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Apr 2020 21:46:58 +0200 Subject: [PATCH 07/27] Add another option for percentile exttremes --- .../Runtime/Debug/DebugExposure.shader | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 599f36210cd..69f32da356d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -12,6 +12,8 @@ Shader "Hidden/HDRP/DebugExposure" #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch +#define PERCENTILE_AS_BARS 1 + // REMOVE #pragma enable_d3d11_debug_symbols @@ -182,7 +184,22 @@ Shader "Hidden/HDRP/DebugExposure" if (uv.y < val) { isEdgeOfBin = isEdgeOfBin || (uv.y > val - _ScreenSize.w); - +#if PERCENTILE_AS_BARS == 0 + uint bin = uint((unormCoord.x * HISTOGRAM_BINS) / (_ScreenSize.x)); + if (bin == uint(minPercentLoc)) + { + outColor.rgb = float3(0, 0, 1); + } + else if(bin == uint(maxPercentLoc)) + { + outColor.rgb = float3(1, 0, 0); + } + else if (bin < uint(minPercentLoc) || bin > uint(maxPercentLoc)) + { + outColor.rgb = float3(0.25, 0.25, 0.25); + } + else +#endif outColor.rgb = float3(1.0f, 1.0f, 1.0f); if (isEdgeOfBin) outColor.rgb = 0; } @@ -190,13 +207,13 @@ Shader "Hidden/HDRP/DebugExposure" // ---- Draw indicators ---- float currExposure = _ExposureTexture[int2(0, 0)].y; float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - DrawHistogramIndicatorBar(unormCoord.xy, evInRange, 0.002f, 0.05, outColor); + DrawHistogramIndicatorBar(unormCoord.xy, evInRange, 0.002f, float3(0.05f, 0.05f, 0.05f), outColor); // Find location for percentiles bars. - +#if PERCENTILE_AS_BARS DrawHistogramIndicatorBar(unormCoord.xy, minPercentLoc, 0.002f, float3(0, 0, 1), outColor); DrawHistogramIndicatorBar(unormCoord.xy, maxPercentLoc, 0.002f, float3(1, 0, 0), outColor); - +#endif // ---- Draw labels ---- // Number of labels @@ -322,8 +339,13 @@ Shader "Hidden/HDRP/DebugExposure" } float histFrameHeight = 0.2 * _RTHandleScale.y; - float minPercentileLoc = minPercentileBin / (HISTOGRAM_BINS-1); - float maxPercentileLoc = maxPercentileBin / (HISTOGRAM_BINS-1); + float minPercentileLoc = max(minPercentileBin, 0); + float maxPercentileLoc = min(maxPercentileBin, HISTOGRAM_BINS - 1); +#if PERCENTILE_AS_BARS + minPercentileLoc /= (HISTOGRAM_BINS - 1); + maxPercentileLoc /= (HISTOGRAM_BINS - 1); +#endif + DrawHistogramFrame(uv, input.positionCS.xy, histFrameHeight, ToHeat(uv.x), 0.1f, maxValue, minPercentileLoc, maxPercentileLoc, outputColor); From db33844a248e46654f673b4266471e67bc02db2d Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Apr 2020 10:03:40 +0200 Subject: [PATCH 08/27] fix warning --- .../Runtime/Debug/DebugExposure.shader | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 69f32da356d..3feecf44118 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -56,7 +56,7 @@ Shader "Hidden/HDRP/DebugExposure" void DrawHeatSideBar(float2 uv, float2 startSidebar, float2 endSidebar, float evValueRange, float3 indicatorColor, float2 sidebarSize, inout float3 sidebarColor) { float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; - uint indicatorHalfSize = 5; + int indicatorHalfSize = 5; if (all(uv > startSidebar) && all(uv < endSidebar)) { @@ -140,7 +140,7 @@ Shader "Hidden/HDRP/DebugExposure" return sumBelowValue / histSum; } - void DrawHistogramIndicatorBar(uint coord, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) + void DrawHistogramIndicatorBar(float coord, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) { float halfWidthInScreen = widthNDC * _ScreenSize.x; float minScreenPos = (uvXLocation - widthNDC * 0.5) * _ScreenSize.x; @@ -207,12 +207,12 @@ Shader "Hidden/HDRP/DebugExposure" // ---- Draw indicators ---- float currExposure = _ExposureTexture[int2(0, 0)].y; float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - DrawHistogramIndicatorBar(unormCoord.xy, evInRange, 0.002f, float3(0.05f, 0.05f, 0.05f), outColor); + DrawHistogramIndicatorBar(float(unormCoord.x), evInRange, 0.002f, float3(0.05f, 0.05f, 0.05f), outColor); // Find location for percentiles bars. #if PERCENTILE_AS_BARS - DrawHistogramIndicatorBar(unormCoord.xy, minPercentLoc, 0.002f, float3(0, 0, 1), outColor); - DrawHistogramIndicatorBar(unormCoord.xy, maxPercentLoc, 0.002f, float3(1, 0, 0), outColor); + DrawHistogramIndicatorBar(float(unormCoord.x), minPercentLoc, 0.002f, float3(0, 0, 1), outColor); + DrawHistogramIndicatorBar(float(unormCoord.x), maxPercentLoc, 0.002f, float3(1, 0, 0), outColor); #endif // ---- Draw labels ---- From a277a564869b1a803b5850319e51345b15782d25 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Apr 2020 11:00:00 +0200 Subject: [PATCH 09/27] Moving debug modes --- .../Runtime/Debug/DebugDisplay.cs | 37 ++++++++++--------- .../Runtime/Debug/LightingDebug.cs | 20 ++++++++++ .../Runtime/Debug/SceneExposureDebug.cs | 33 ----------------- .../Runtime/Debug/SceneExposureDebug.cs.meta | 11 ------ .../PostProcessing/Shaders/Exposure.compute | 20 +--------- .../Shaders/ExposureCommon.hlsl | 5 --- .../RenderPipeline/HDRenderPipeline.cs | 7 ++-- 7 files changed, 43 insertions(+), 90 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 30c51fa85c0..1347a1975f1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -181,8 +181,6 @@ public class DebugData public MipMapDebugSettings mipMapDebugSettings = new MipMapDebugSettings(); /// Current color picker debug settings. public ColorPickerDebugSettings colorPickerDebugSettings = new ColorPickerDebugSettings(); - /// Current exposure debug settings. - public ExposureDebugSettings exposureDebugSettings = new ExposureDebugSettings(); // TODO_FCC: TODO Check where to put this. /// Current false color debug settings. public FalseColorDebugSettings falseColorDebugSettings = new FalseColorDebugSettings(); /// Current decals debug settings. @@ -428,7 +426,7 @@ public bool IsDebugFullScreenEnabled() /// True if any full screen exposure debug display is enabled. public bool IsDebugExposureModeEnabled() { - return data.exposureDebugSettings.debugMode != ExposureDebugMode.None; + return data.lightingDebugSettings.exposureDebugMode != ExposureDebugMode.None; } /// @@ -638,6 +636,15 @@ internal void SetProbeVolumeAtlasSliceMode(ProbeVolumeAtlasSliceMode value) data.lightingDebugSettings.probeVolumeAtlasSliceMode = value; } + /// + /// Set the current Exposure Debug Mode. + /// + /// Desired Probe Volume Debug Mode. + internal void SetExposureDebugMode(ExposureDebugMode value) + { + data.lightingDebugSettings.exposureDebugMode = value; + } + /// /// Set the current Mip Map Debug Mode. /// @@ -884,6 +891,15 @@ void RegisterLightingDebug() } }); + lighting.children.Add(new DebugUI.Foldout + { + displayName = "Exposure ", + children = { + new DebugUI.EnumField { displayName = "Debug Mode", getter = () => (int)data.lightingDebugSettings.exposureDebugMode, setter = value => SetExposureDebugMode((ExposureDebugMode)value), autoEnum = typeof(ExposureDebugMode), onValueChanged = RefreshLightingDebug, getIndex = () => data.exposureDebugModeEnumIndex, setIndex = value => data.exposureDebugModeEnumIndex = value }, + new DebugUI.FloatField { displayName = "Debug Exposure Compensation", getter = () => data.lightingDebugSettings.debugExposure, setter = value => data.lightingDebugSettings.debugExposure = value } + } + }); + lighting.children.Add(new DebugUI.EnumField { displayName = "Debug Mode", getter = () => (int)data.lightingDebugSettings.debugLightingMode, setter = value => SetDebugLightingMode((DebugLightingMode)value), autoEnum = typeof(DebugLightingMode), onValueChanged = RefreshLightingDebug, getIndex = () => data.lightingDebugModeEnumIndex, setIndex = value => { data.ResetExclusiveEnumIndices(); data.lightingDebugModeEnumIndex = value; } }); lighting.children.Add(new DebugUI.BitField { displayName = "Hierarchy Debug Mode", getter = () => data.lightingDebugSettings.debugLightFilterMode, setter = value => SetDebugLightFilterMode((DebugLightFilterMode)value), enumType = typeof(DebugLightFilterMode), onValueChanged = RefreshLightingDebug, }); @@ -1137,8 +1153,6 @@ void RegisterLightingDebug() list.Add(new DebugUI.FloatField { displayName = "Debug Overlay Screen Ratio", getter = () => data.debugOverlayRatio, setter = v => data.debugOverlayRatio = v, min = () => 0.1f, max = () => 1f}); - list.Add(new DebugUI.FloatField { displayName = "Debug Exposure Compensation", getter = () => data.lightingDebugSettings.debugExposure, setter = value => data.lightingDebugSettings.debugExposure = value }); - m_DebugLightingItems = list.ToArray(); var panel = DebugManager.instance.GetPanel(k_PanelLighting, true); panel.children.Add(m_DebugLightingItems); @@ -1400,19 +1414,6 @@ void RegisterRenderingDebug() } }); - widgetList.AddRange(new[] -{ - new DebugUI.Container - { - displayName = "Exposure", - children = - { - new DebugUI.EnumField { displayName = "Debug Mode", getter = () => (int)data.exposureDebugSettings.debugMode, setter = value => data.exposureDebugSettings.debugMode = (ExposureDebugMode)value, autoEnum = typeof(ExposureDebugMode), getIndex = () => data.exposureDebugModeEnumIndex, setIndex = value => data.exposureDebugModeEnumIndex = value }, - } - } - }); - - widgetList.Add(new DebugUI.BoolField { displayName = "False Color Mode", getter = () => data.falseColorDebugSettings.falseColor, setter = value => data.falseColorDebugSettings.falseColor = value, onValueChanged = RefreshRenderingDebug }); if (data.falseColorDebugSettings.falseColor) { diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs index 2ca520cafff..9c41ff778ad 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -168,6 +168,24 @@ public enum ShadowMapDebugMode SingleShadow, } + /// + /// Exposure debug mode. + /// + [GenerateHLSL] + public enum ExposureDebugMode + { + /// No exposure debug. + None, + /// Display the EV100 values of the scene, color-coded. + SceneEV100Values, + /// Display the Histogram used for exposure. + HistogramView, + /// Visualize the scene color weighted as the metering mode selected. + MeteringWeighted, + + } + + /// /// Probe Volume Debug Modes. /// @@ -291,6 +309,8 @@ public bool IsDebugDisplayEnabled() /// Maximum number of lights against which the light overdraw gradient is displayed. public uint maxDebugLightCount = 24; + /// Exposure debug mode. + public ExposureDebugMode exposureDebugMode = ExposureDebugMode.None; /// Exposure compensation to apply on current scene exposure. public float debugExposure = 0.0f; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs deleted file mode 100644 index 63a36782da7..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace UnityEngine.Rendering.HighDefinition -{ - /// - /// Color Picker Debug Mode. - /// - [GenerateHLSL] - public enum ExposureDebugMode - { - /// No exposure debug. - None, - /// TODO_FCC ADD TODO. - SceneEV100Values, - /// TODO_FCC ADD TODO - HistogramView, - /// TODO_FCC Visualize metering - MeteringWeighted, - - } - - /// - /// Exposure debug settings. - /// - [Serializable] - public class ExposureDebugSettings - { - /// - /// Exposure picker mode. - /// - public ExposureDebugMode debugMode = ExposureDebugMode.None; - } -} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta deleted file mode 100644 index def02b50d9e..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/SceneExposureDebug.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b2b7dd93929f3044ca05cd5608ff49c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute index 5b0e781a747..aff1cc70e65 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute @@ -39,21 +39,6 @@ void KManualCameraExposure(uint2 dispatchThreadId : SV_DispatchThreadID) _OutputTexture[dispatchThreadId] = float2(ConvertEV100ToExposure(ev100), ev100); } - -// TODO_FCC: REMOVE THIS. -uint GetHistogramBinLocation(float value) -{ - float scaledLogLuma = ComputeEV100FromAvgLuminance(value) * 0.0333333333f + 0.33333333333; - return uint(saturate(scaledLogLuma) * (128 - 1)); -} -// TODO_FCC: REMOVE THIS. -float BinLocationToLogLuma(uint binIdx) -{ - return (binIdx * rcp(float(128 - 1)) - 0.33333333333) / 0.0333333333f; -} - - - // // Average luminance pre-pass // Transforms the input to log luminance in a square-POT target @@ -70,11 +55,8 @@ void KPrePass(uint2 dispatchThreadId : SV_DispatchThreadID) float weight = WeightSample(dispatchThreadId, PREPASS_TEX_SIZE.xx); - uint bin = GetHistogramBinLocation(luma); - float value = BinLocationToLogLuma(bin); - float logLuma = ComputeEV100FromAvgLuminance(max(luma, 1e-4)); - _OutputTexture[posInputs.positionSS] = float2(value, weight); + _OutputTexture[posInputs.positionSS] = float2(logLuma, weight); } // diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl index 27143114442..28a9cdad9f7 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl @@ -32,11 +32,6 @@ CBUFFER_END #define ParamAdaptationMode _Variants.z #define ParamEvaluateMode _Variants.w -// TODO_FCC: IMPORTANT! This function uses hard coded values for the texture that is output by the prepass. -// Need to make the analytical metering texture size independent. -// When that is done, these defines should be moved back to Exposure.compute - - float GetPreviousExposureEV100() { return _PreviousExposureTexture[uint2(0u, 0u)].y; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 2f8b96fcec7..688ccfa24a5 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4266,7 +4266,7 @@ void PushColorPickerDebugTexture(CommandBuffer cmd, HDCamera hdCamera, RTHandle bool NeedExposureDebugMode(DebugDisplaySettings debugSettings) { - return debugSettings.data.exposureDebugSettings.debugMode != ExposureDebugMode.None; + return debugSettings.data.lightingDebugSettings.exposureDebugMode != ExposureDebugMode.None; } bool NeedsFullScreenDebugMode() @@ -4445,9 +4445,9 @@ static void RenderExposureDebug(in DebugParameters parameters, int passIndex = 0; - if (parameters.debugDisplaySettings.data.exposureDebugSettings.debugMode == ExposureDebugMode.MeteringWeighted) + if (parameters.debugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.MeteringWeighted) passIndex = 1; - if (parameters.debugDisplaySettings.data.exposureDebugSettings.debugMode == ExposureDebugMode.HistogramView) + if (parameters.debugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.HistogramView) passIndex = 2; HDUtils.DrawFullScreen(cmd, parameters.debugExposureMaterial, output, null, passIndex); @@ -4495,7 +4495,6 @@ void RenderDebug(HDCamera hdCamera, CommandBuffer cmd, CullingResults cullResult PushColorPickerDebugTexture(cmd, hdCamera, m_IntermediateAfterPostProcessBuffer); } - // TODO_FCC: Should this be inside the fullscreen debug ? Probably... if (debugParams.exposureDebugEnabled) { RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); From c533cfd1218942df8b9a146c4c5d4c57c1541512 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Apr 2020 14:28:54 +0200 Subject: [PATCH 10/27] Label bar separate (invisible otherwise) --- .../Runtime/Debug/DebugExposure.shader | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 3feecf44118..6aed782ac62 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -155,6 +155,7 @@ Shader "Hidden/HDRP/DebugExposure" void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, float maxHist, float minPercentLoc, float maxPercentLoc, inout float3 outColor) { float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; + float heightLabelBar = (DEBUG_FONT_TEXT_WIDTH * 1.25) * _ScreenSize.w * _RTHandleScale.y; if (uv.y > frameHeight) return; @@ -174,14 +175,22 @@ Shader "Hidden/HDRP/DebugExposure" outColor = lerp(outColor, backgroundColor, alpha); } + // ---- Draw label bar ----- + if (uv.y < heightLabelBar) + { + outColor = outColor * 0.075f; + } + // ---- Draw Buckets frame ---- bool isEdgeOfBin = false; float val = GetHistogramValue(unormCoord.x, isEdgeOfBin); val /= maxHist; - val *= (frameHeight * 0.9); - if (uv.y < val) + val *= 0.95*(frameHeight - heightLabelBar); + val += heightLabelBar; + + if (uv.y < val && uv.y > heightLabelBar) { isEdgeOfBin = isEdgeOfBin || (uv.y > val - _ScreenSize.w); #if PERCENTILE_AS_BARS == 0 @@ -207,13 +216,17 @@ Shader "Hidden/HDRP/DebugExposure" // ---- Draw indicators ---- float currExposure = _ExposureTexture[int2(0, 0)].y; float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - DrawHistogramIndicatorBar(float(unormCoord.x), evInRange, 0.002f, float3(0.05f, 0.05f, 0.05f), outColor); - // Find location for percentiles bars. + if (uv.y > heightLabelBar) + { + DrawHistogramIndicatorBar(float(unormCoord.x), evInRange, 0.003f, float3(0.05f, 0.05f, 0.05f), outColor); + // Find location for percentiles bars. #if PERCENTILE_AS_BARS - DrawHistogramIndicatorBar(float(unormCoord.x), minPercentLoc, 0.002f, float3(0, 0, 1), outColor); - DrawHistogramIndicatorBar(float(unormCoord.x), maxPercentLoc, 0.002f, float3(1, 0, 0), outColor); + DrawHistogramIndicatorBar(float(unormCoord.x), minPercentLoc, 0.003f, float3(0, 0, 1), outColor); + DrawHistogramIndicatorBar(float(unormCoord.x), maxPercentLoc, 0.003f, float3(1, 0, 0), outColor); #endif + } + // ---- Draw labels ---- // Number of labels @@ -224,7 +237,7 @@ Shader "Hidden/HDRP/DebugExposure" int minLabelLocationX = DEBUG_FONT_TEXT_WIDTH * 0.25; int maxLabelLocationX = _ScreenSize.x - (DEBUG_FONT_TEXT_WIDTH * 3); - int labelLocationY = DEBUG_FONT_TEXT_WIDTH * 0.15; + int labelLocationY = 0.0f; [unroll] for (int i = 0; i <= labelCount; ++i) @@ -232,7 +245,7 @@ Shader "Hidden/HDRP/DebugExposure" float t = oneOverLabelCount * i; float labelValue = lerp(ParamExposureLimitMin, ParamExposureLimitMax, t); uint2 labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY); - DrawFloatExplicitPrecision(labelValue, float3(1.0f, 0.0f, 0.0f), unormCoord, 1, labelLoc, outColor.rgb); + DrawFloatExplicitPrecision(labelValue, float3(1.0f, 1.0f, 1.0f), unormCoord, 1, labelLoc, outColor.rgb); } } From 8cca38f9459a8e6cb7821f49a66a3aa70f37524c Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Apr 2020 15:44:51 +0200 Subject: [PATCH 11/27] Push change to bar indicator --- .../Runtime/Debug/DebugExposure.shader | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 6aed782ac62..0a8aba8d513 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -12,7 +12,7 @@ Shader "Hidden/HDRP/DebugExposure" #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch -#define PERCENTILE_AS_BARS 1 +#define PERCENTILE_AS_BARS 0 // REMOVE #pragma enable_d3d11_debug_symbols @@ -195,18 +195,14 @@ Shader "Hidden/HDRP/DebugExposure" isEdgeOfBin = isEdgeOfBin || (uv.y > val - _ScreenSize.w); #if PERCENTILE_AS_BARS == 0 uint bin = uint((unormCoord.x * HISTOGRAM_BINS) / (_ScreenSize.x)); - if (bin == uint(minPercentLoc)) + if (bin <= uint(minPercentLoc)) { outColor.rgb = float3(0, 0, 1); } - else if(bin == uint(maxPercentLoc)) + else if(bin >= uint(maxPercentLoc)) { outColor.rgb = float3(1, 0, 0); } - else if (bin < uint(minPercentLoc) || bin > uint(maxPercentLoc)) - { - outColor.rgb = float3(0.25, 0.25, 0.25); - } else #endif outColor.rgb = float3(1.0f, 1.0f, 1.0f); From f31915665eb7ce8ba968939a5bf72195a82c55bb Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Apr 2020 16:57:54 +0200 Subject: [PATCH 12/27] remove fancy background of histogram frame --- .../Runtime/Debug/DebugExposure.shader | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 0a8aba8d513..8a4d9c836f5 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -152,6 +152,8 @@ Shader "Hidden/HDRP/DebugExposure" } } + // void DrawHistogram + void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, float maxHist, float minPercentLoc, float maxPercentLoc, inout float3 outColor) { float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; @@ -355,7 +357,7 @@ Shader "Hidden/HDRP/DebugExposure" maxPercentileLoc /= (HISTOGRAM_BINS - 1); #endif - DrawHistogramFrame(uv, input.positionCS.xy, histFrameHeight, ToHeat(uv.x), 0.1f, maxValue, minPercentileLoc, maxPercentileLoc, outputColor); + DrawHistogramFrame(uv, input.positionCS.xy, histFrameHeight, float3(0.125,0.125,0.125), 0.4f, maxValue, minPercentileLoc, maxPercentileLoc, outputColor); return outputColor;// lerp(, color, 0.025f); From 7fc3237c2cb7dafc622a100211d1b5d69bcaa874 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 4 May 2020 13:25:54 +0200 Subject: [PATCH 13/27] Small triangle instead of indicator bars --- .../Runtime/Debug/DebugExposure.shader | 125 ++++++++++++------ 1 file changed, 88 insertions(+), 37 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 8a4d9c836f5..8555faf6a51 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -8,14 +8,11 @@ Shader "Hidden/HDRP/DebugExposure" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" #pragma vertex Vert - +#pragma enable_d3d11_debug_symbols // TODO_FCC: REMOVE #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch -#define PERCENTILE_AS_BARS 0 - - // REMOVE -#pragma enable_d3d11_debug_symbols + #define PERCENTILE_AS_BARS 0 struct Attributes { @@ -60,9 +57,9 @@ Shader "Hidden/HDRP/DebugExposure" if (all(uv > startSidebar) && all(uv < endSidebar)) { - float inRange = (uv.y - startSidebar.y) / (endSidebar.y - startSidebar.y); + float inRange = (uv.x - startSidebar.x) / (endSidebar.x - startSidebar.x); evValueRange = clamp(evValueRange, 0.0f, 1.0f); - int distanceInPixels = abs(evValueRange - inRange) * sidebarSize.y * _ScreenSize.y; + int distanceInPixels = abs(evValueRange - inRange) * sidebarSize.x * _ScreenSize.x; if (distanceInPixels < indicatorHalfSize) { sidebarColor = indicatorColor; @@ -130,7 +127,7 @@ Shader "Hidden/HDRP/DebugExposure" if (maxPercentileBin < 0) { sumForMax += histVal; - if (sumForMax / histSum >= _HistogramMaxPercentile) + if (sumForMax / histSum > _HistogramMaxPercentile) { maxPercentileBin = i; } @@ -152,7 +149,25 @@ Shader "Hidden/HDRP/DebugExposure" } } - // void DrawHistogram + void DrawTriangleIndicator(float2 coord, float labelBarHeight, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) + { + float halfWidthInScreen = widthNDC * _ScreenSize.x; + float heightInIndicator = (coord.y / labelBarHeight); + float indicatorWidth = 1.0f - heightInIndicator; + + float minScreenPos = (uvXLocation - widthNDC * indicatorWidth * 0.5) * _ScreenSize.x; + float maxScreenPos = (uvXLocation + widthNDC * indicatorWidth * 0.5) * _ScreenSize.x; + + if (coord.x > minScreenPos && coord.x < maxScreenPos) + { + outColor = color; + } + else if (coord.x > minScreenPos - 2 && coord.x < maxScreenPos + 2) + { + outColor = 0; + } + + } void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, float maxHist, float minPercentLoc, float maxPercentLoc, inout float3 outColor) { @@ -196,12 +211,12 @@ Shader "Hidden/HDRP/DebugExposure" { isEdgeOfBin = isEdgeOfBin || (uv.y > val - _ScreenSize.w); #if PERCENTILE_AS_BARS == 0 - uint bin = uint((unormCoord.x * HISTOGRAM_BINS) / (_ScreenSize.x)); - if (bin <= uint(minPercentLoc)) + uint bin = uint((unormCoord.x * (HISTOGRAM_BINS)) / (_ScreenSize.x)); + if (bin <= uint(minPercentLoc) && minPercentLoc > 0) { outColor.rgb = float3(0, 0, 1); } - else if(bin >= uint(maxPercentLoc)) + else if(bin >= uint(maxPercentLoc) && maxPercentLoc > 0) { outColor.rgb = float3(1, 0, 0); } @@ -211,20 +226,6 @@ Shader "Hidden/HDRP/DebugExposure" if (isEdgeOfBin) outColor.rgb = 0; } - // ---- Draw indicators ---- - float currExposure = _ExposureTexture[int2(0, 0)].y; - float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - - if (uv.y > heightLabelBar) - { - DrawHistogramIndicatorBar(float(unormCoord.x), evInRange, 0.003f, float3(0.05f, 0.05f, 0.05f), outColor); - // Find location for percentiles bars. -#if PERCENTILE_AS_BARS - DrawHistogramIndicatorBar(float(unormCoord.x), minPercentLoc, 0.003f, float3(0, 0, 1), outColor); - DrawHistogramIndicatorBar(float(unormCoord.x), maxPercentLoc, 0.003f, float3(1, 0, 0), outColor); -#endif - } - // ---- Draw labels ---- // Number of labels @@ -245,6 +246,28 @@ Shader "Hidden/HDRP/DebugExposure" uint2 labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY); DrawFloatExplicitPrecision(labelValue, float3(1.0f, 1.0f, 1.0f), unormCoord, 1, labelLoc, outColor.rgb); } + + // ---- Draw indicators ---- + float currExposure = _ExposureTexture[int2(0, 0)].y; + float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); + + float2 halfIndicatorSize = 0.007f; + float halfWidthInScreen = halfIndicatorSize * _ScreenSize.x; + + float labelFrameHeightScreen = heightLabelBar * (_ScreenSize.y / _RTHandleScale.y); + + if (uv.y < heightLabelBar) + { + DrawTriangleIndicator(float2(unormCoord.xy), labelFrameHeightScreen, evInRange, halfIndicatorSize, float3(0.9f, 0.75f, 0.1f), outColor); + DrawTriangleIndicator(float2(unormCoord.xy), labelFrameHeightScreen, evInRange, halfIndicatorSize, float3(0.15f, 0.15f, 0.1f), outColor); + + // Find location for percentiles bars. +#if PERCENTILE_AS_BARS + DrawHistogramIndicatorBar(float(unormCoord.x), minPercentLoc, 0.003f, float3(0, 0, 1), outColor); + DrawHistogramIndicatorBar(float(unormCoord.x), maxPercentLoc, 0.003f, float3(1, 0, 0), outColor); +#endif + } + } @@ -266,10 +289,9 @@ Shader "Hidden/HDRP/DebugExposure" float3 textColor = 0.0f; - // TODO: Should they be in pixels? ASK UX! - float2 sidebarSize = float2(0.025, 0.7); + float2 sidebarSize = float2(0.9, 0.02); - float2 sidebarBottomLeft = float2(0.04, (1.0 - sidebarSize.y) * 0.5) * _RTHandleScale.xy; + float2 sidebarBottomLeft = float2(0.05, 0.02) * _RTHandleScale.xy; float2 endPointSidebar = sidebarBottomLeft + sidebarSize * _RTHandleScale.xy; float3 outputColor = 0; @@ -299,15 +321,44 @@ Shader "Hidden/HDRP/DebugExposure" int2 unormCoord = input.positionCS.xy; - int2 labelEVMinLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), 0); - int2 textLocation = labelEVMinLoc; - DrawFloatExplicitPrecision(ParamExposureLimitMin, textColor, unormCoord, 1, textLocation, outputColor.rgb); - int2 labelEVMaxLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), sidebarSize.y * 0.98 * _ScreenSize.y); - textLocation = labelEVMaxLoc; - DrawFloatExplicitPrecision(ParamExposureLimitMax, textColor, unormCoord, 1, textLocation, outputColor.rgb); + float heightLabelBar = (DEBUG_FONT_TEXT_WIDTH * 1.25f) * _ScreenSize.w * _RTHandleScale.y; + // Label bar + float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; + if (uv.y + (sidebarSize.y * _RTHandleScale.y) < endPointSidebar.y && + uv.x >= (sidebarBottomLeft.x - borderSize.x) && uv.x <= (borderSize.x + endPointSidebar.x)) + { + outputColor = outputColor * 0.075f; + } + + // Number of labels + int labelCount = 8; + float oneOverLabelCount = rcp(labelCount); + float labelDeltaScreenSpace = _ScreenSize.x * oneOverLabelCount; + + int minLabelLocationX = (sidebarBottomLeft.x - borderSize.x) *_ScreenSize.x + DEBUG_FONT_TEXT_WIDTH * 0.25; + int maxLabelLocationX = (borderSize.x + endPointSidebar.x) *_ScreenSize.x - (DEBUG_FONT_TEXT_WIDTH * 3); + + int labelLocationY = 0.0f; + + [unroll] + for (int i = 0; i <= labelCount; ++i) + { + float t = oneOverLabelCount * i; + float labelValue = lerp(ParamExposureLimitMin, ParamExposureLimitMax, t); + uint2 labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY); + DrawFloatExplicitPrecision(labelValue, float3(1.0f, 1.0f, 1.0f), unormCoord, 1, labelLoc, outputColor.rgb); + } + + + //int2 labelEVMinLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), 0); + //int2 textLocation = labelEVMinLoc; + //DrawFloatExplicitPrecision(ParamExposureLimitMin, textColor, unormCoord, 1, textLocation, outputColor.rgb); + //int2 labelEVMaxLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), sidebarSize.y * 0.98 * _ScreenSize.y); + //textLocation = labelEVMaxLoc; + //DrawFloatExplicitPrecision(ParamExposureLimitMax, textColor, unormCoord, 1, textLocation, outputColor.rgb); int displayTextOffsetX = DEBUG_FONT_TEXT_WIDTH; - textLocation = int2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); + int2 textLocation = int2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); DrawFloatExplicitPrecision(indicatorEV, textColor, unormCoord, 1, textLocation, outputColor.rgb); @@ -360,7 +411,7 @@ Shader "Hidden/HDRP/DebugExposure" DrawHistogramFrame(uv, input.positionCS.xy, histFrameHeight, float3(0.125,0.125,0.125), 0.4f, maxValue, minPercentileLoc, maxPercentileLoc, outputColor); - return outputColor;// lerp(, color, 0.025f); + return outputColor; } ENDHLSL From 2573a9d4547f2435c8cb4c110c82d1ffa3c89017 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 4 May 2020 14:54:54 +0200 Subject: [PATCH 14/27] Target exposure indicator --- .../Runtime/Debug/DebugExposure.shader | 15 ++++++++----- .../PostProcessing/PostProcessSystem.cs | 22 +++++++++++++++++++ .../Shaders/HistogramExposure.compute | 10 ++++----- .../Shaders/HistogramExposureCommon.hlsl | 6 +++++ .../RenderPipeline/HDRenderPipeline.cs | 6 ++++- .../RenderPipeline/HDStringConstants.cs | 1 + 6 files changed, 48 insertions(+), 12 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 8555faf6a51..55333337fd9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -152,21 +152,23 @@ Shader "Hidden/HDRP/DebugExposure" void DrawTriangleIndicator(float2 coord, float labelBarHeight, float uvXLocation, float widthNDC, float3 color, inout float3 outColor) { float halfWidthInScreen = widthNDC * _ScreenSize.x; - float heightInIndicator = (coord.y / labelBarHeight); + float arrowStart = labelBarHeight * 0.4f; + + float heightInIndicator = ((coord.y - arrowStart) / (labelBarHeight - arrowStart)); float indicatorWidth = 1.0f - heightInIndicator; float minScreenPos = (uvXLocation - widthNDC * indicatorWidth * 0.5) * _ScreenSize.x; float maxScreenPos = (uvXLocation + widthNDC * indicatorWidth * 0.5) * _ScreenSize.x; - if (coord.x > minScreenPos && coord.x < maxScreenPos) + uint triangleBorder = 2; + if (coord.x > minScreenPos && coord.x < maxScreenPos && coord.y >= arrowStart) { outColor = color; } - else if (coord.x > minScreenPos - 2 && coord.x < maxScreenPos + 2) + else if (coord.x > minScreenPos - triangleBorder && coord.x < maxScreenPos + triangleBorder && coord.y > arrowStart - triangleBorder) { outColor = 0; } - } void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, float maxHist, float minPercentLoc, float maxPercentLoc, inout float3 outColor) @@ -249,7 +251,10 @@ Shader "Hidden/HDRP/DebugExposure" // ---- Draw indicators ---- float currExposure = _ExposureTexture[int2(0, 0)].y; + float targetExposure = _ExposureDebugTexture[int2(0, 0)].x; + float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); + float targetEVInRange = (targetExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); float2 halfIndicatorSize = 0.007f; float halfWidthInScreen = halfIndicatorSize * _ScreenSize.x; @@ -258,7 +263,7 @@ Shader "Hidden/HDRP/DebugExposure" if (uv.y < heightLabelBar) { - DrawTriangleIndicator(float2(unormCoord.xy), labelFrameHeightScreen, evInRange, halfIndicatorSize, float3(0.9f, 0.75f, 0.1f), outColor); + DrawTriangleIndicator(float2(unormCoord.xy), labelFrameHeightScreen, targetEVInRange, halfIndicatorSize, float3(0.9f, 0.75f, 0.1f), outColor); DrawTriangleIndicator(float2(unormCoord.xy), labelFrameHeightScreen, evInRange, halfIndicatorSize, float3(0.15f, 0.15f, 0.1f), outColor); // Find location for percentiles bars. diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index 9746b8ba4ca..6a5e8d86d51 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -40,6 +40,7 @@ private enum SMAAStage Texture2D m_ExposureCurveTexture; RTHandle m_EmptyExposureTexture; // RGHalf + RTHandle m_DebugExposureData; ComputeBuffer m_HistogramBuffer; readonly int[] m_EmptyHistogram = new int[k_HistogramBins]; @@ -189,6 +190,11 @@ public PostProcessSystem(HDRenderPipelineAsset hdAsset, RenderPipelineResources enableRandomWrite: true, name: "Empty EV100 Exposure" ); + m_DebugExposureData = RTHandles.Alloc(1, 1, colorFormat: k_ExposureFormat, + enableRandomWrite: true, name: "Debug Exposure Info" + ); + + m_MotionBlurSupportsScattering = SystemInfo.IsFormatSupported(GraphicsFormat.R32_UInt, FormatUsage.LoadStore) && SystemInfo.IsFormatSupported(GraphicsFormat.R16_UInt, FormatUsage.LoadStore); // TODO: Remove this line when atomic bug in HLSLcc is fixed. m_MotionBlurSupportsScattering = m_MotionBlurSupportsScattering && (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Vulkan); @@ -241,6 +247,7 @@ public void Cleanup() m_Pool.Cleanup(); RTHandles.Release(m_EmptyExposureTexture); + RTHandles.Release(m_DebugExposureData); RTHandles.Release(m_TempTexture1024); RTHandles.Release(m_TempTexture32); RTHandles.Release(m_AlphaTexture); @@ -260,6 +267,7 @@ public void Cleanup() CoreUtils.SafeRelease(m_ContrastAdaptiveSharpen); m_EmptyExposureTexture = null; + m_DebugExposureData = null; m_TempTexture1024 = null; m_TempTexture32 = null; m_AlphaTexture = null; @@ -286,6 +294,7 @@ void CheckRenderTexturesValidity() if (!m_EmptyExposureTexture.rt.IsCreated()) FillEmptyExposureTexture(); + HDUtils.CheckRTCreated(m_DebugExposureData.rt); HDUtils.CheckRTCreated(m_InternalLogLut.rt); HDUtils.CheckRTCreated(m_TempTexture1024.rt); HDUtils.CheckRTCreated(m_TempTexture32.rt); @@ -775,6 +784,11 @@ public RTHandle GetPreviousExposureTexture(HDCamera camera) return rt ?? m_EmptyExposureTexture; } + public RTHandle GetExposureDebugData() + { + return m_DebugExposureData; + } + public ComputeBuffer GetHistogramBuffer() { return m_HistogramBuffer; @@ -933,6 +947,7 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourceTexture) { var cs = m_Resources.shaders.histogramExposureCS; + cs.shaderKeywords = null; int kernel; GrabExposureHistoryTextures(camera, out var prevExposure, out var nextExposure); @@ -950,6 +965,7 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc prevExposure = m_EmptyExposureTexture; // Use neutral texture } + // TODO_FCC TODO: Make this generic setup in a function so that we can share with dynamic exposure. m_ExposureVariants[0] = 1; // (int)exposureSettings.luminanceSource.value; m_ExposureVariants[1] = (int)m_Exposure.meteringMode.value; m_ExposureVariants[2] = (int)adaptationMode; @@ -997,6 +1013,12 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._OutputTexture, nextExposure); + if (m_HDInstance.m_CurrentDebugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.HistogramView) + { + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureDebugTexture, m_DebugExposureData); + cs.EnableKeyword("OUTPUT_DEBUG_DATA"); + } + cmd.DispatchCompute(cs, kernel, 1, 1, 1); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index e525f76475a..40cc104e06e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -1,7 +1,6 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl" -#pragma enable_d3d11_debug_symbols // TODO List to investigate // - Number of bins: @@ -10,16 +9,12 @@ // - At the moment the dispatch is at half res, but the buffer sampled is full res, // causing fairly bad cache behaviour. Can we use the mip chain realistically without issues? [The one we have is blurred and might be incomplete?] -// NOTE: fairly naive for now. - -// TODO: Do mapping to 0.18 instead of 1 ? - - #pragma kernel KHistogramGen GEN_PASS #pragma kernel KHistogramReduce REDUCE_PASS #define GROUP_SIZE_X 16 #define GROUP_SIZE_Y 8 +#pragma multi_compile _ OUTPUT_DEBUG_DATA // Because atomics are only on uint and we need a weighted value, we need to convert. // If we multiply the weight by 2048, we get somewhat ok precision and we support up to @@ -178,6 +173,9 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) float exposure = AdaptExposure(avgEV - ParamExposureCompensation); exposure = clamp(exposure, ParamExposureLimitMin, ParamExposureLimitMax); _OutputTexture[uint2(0, 0)] = float2(ConvertEV100ToExposure(exposure), exposure); +#ifdef OUTPUT_DEBUG_DATA + _ExposureDebugTexture[uint2(0, 0)] = float2(avgEV - ParamExposureCompensation, 0.0f); +#endif } diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl index 5a046251fa4..e1abfe6a5cb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl @@ -12,6 +12,12 @@ RWStructuredBuffer _HistogramBuffer; StructuredBuffer _HistogramBuffer; #endif +#ifdef OUTPUT_DEBUG_DATA +RW_TEXTURE2D(float2, _ExposureDebugTexture); +#else +TEXTURE2D(_ExposureDebugTexture); +#endif + float UnpackWeight(uint val) { return val * rcp(2048.0f); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 688ccfa24a5..e1e05c9ecb1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4414,6 +4414,7 @@ static void RenderExposureDebug(in DebugParameters parameters, RTHandle inputColorBuffer, RTHandle currentExposure, RTHandle prevExposure, + RTHandle debugExposureData, RTHandle output, ComputeBuffer histogramBuffer, CommandBuffer cmd) @@ -4448,7 +4449,10 @@ static void RenderExposureDebug(in DebugParameters parameters, if (parameters.debugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.MeteringWeighted) passIndex = 1; if (parameters.debugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.HistogramView) + { + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._ExposureDebugTexture, debugExposureData); passIndex = 2; + } HDUtils.DrawFullScreen(cmd, parameters.debugExposureMaterial, output, null, passIndex); } @@ -4497,7 +4501,7 @@ void RenderDebug(HDCamera hdCamera, CommandBuffer cmd, CullingResults cullResult if (debugParams.exposureDebugEnabled) { - RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); + RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), m_PostProcessSystem.GetExposureDebugData(),m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); } // First resolve color picker diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index 150893aa85b..b8148d66117 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -595,6 +595,7 @@ static class HDShaderIDs public static readonly int _ExposureTexture = Shader.PropertyToID("_ExposureTexture"); public static readonly int _PrevExposureTexture = Shader.PropertyToID("_PrevExposureTexture"); public static readonly int _PreviousExposureTexture = Shader.PropertyToID("_PreviousExposureTexture"); + public static readonly int _ExposureDebugTexture = Shader.PropertyToID("_ExposureDebugTexture"); public static readonly int _ExposureParams = Shader.PropertyToID("_ExposureParams"); public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); public static readonly int _HistogramBuffer = Shader.PropertyToID("_HistogramBuffer"); From cda2dce90c8f199e9dfd7c6a8642b77570e71219 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 4 May 2020 15:47:08 +0200 Subject: [PATCH 15/27] add some margin --- .../Runtime/Debug/DebugExposure.shader | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 55333337fd9..19de857a408 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -8,7 +8,6 @@ Shader "Hidden/HDRP/DebugExposure" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" #pragma vertex Vert -#pragma enable_d3d11_debug_symbols // TODO_FCC: REMOVE #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch @@ -50,11 +49,13 @@ Shader "Hidden/HDRP/DebugExposure" } // Returns true if it drew the location of the indicator. - void DrawHeatSideBar(float2 uv, float2 startSidebar, float2 endSidebar, float evValueRange, float3 indicatorColor, float2 sidebarSize, inout float3 sidebarColor) + void DrawHeatSideBar(float2 uv, float2 startSidebar, float2 endSidebar, float evValueRange, float3 indicatorColor, float2 sidebarSize, float extremeMargin, inout float3 sidebarColor) { + float2 extremesSize = float2(extremeMargin, 0); float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; int indicatorHalfSize = 5; + if (all(uv > startSidebar) && all(uv < endSidebar)) { float inRange = (uv.x - startSidebar.x) / (endSidebar.x - startSidebar.x); @@ -73,7 +74,15 @@ Shader "Hidden/HDRP/DebugExposure" sidebarColor = ToHeat(inRange); } } - else if(all(uv > startSidebar - borderSize) && all(uv < endSidebar + borderSize)) + else if (all(uv > startSidebar - extremesSize) && all(uv < endSidebar)) + { + sidebarColor = float3(0,0,0); + } + else if (all(uv > startSidebar) && all(uv < endSidebar + extremesSize)) + { + sidebarColor = float3(1, 1, 1); + } + else if(all(uv > startSidebar - (extremesSize + borderSize)) && all(uv < endSidebar + (extremesSize + borderSize))) { sidebarColor = 0.0f; } @@ -284,7 +293,7 @@ Shader "Hidden/HDRP/DebugExposure" float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); - return color * weight;// lerp(, color, 0.025f); + return color * weight; } float3 FragSceneEV100(Varyings input) : SV_Target @@ -294,10 +303,12 @@ Shader "Hidden/HDRP/DebugExposure" float3 textColor = 0.0f; - float2 sidebarSize = float2(0.9, 0.02); + float2 sidebarSize = float2(0.9, 0.02) * _RTHandleScale.xy; - float2 sidebarBottomLeft = float2(0.05, 0.02) * _RTHandleScale.xy; - float2 endPointSidebar = sidebarBottomLeft + sidebarSize * _RTHandleScale.xy; + float heightLabelBar = (DEBUG_FONT_TEXT_WIDTH * 1.25f) * _ScreenSize.w * _RTHandleScale.y; + + float2 sidebarBottomLeft = float2(0.05 * _RTHandleScale.x, heightLabelBar); + float2 endPointSidebar = sidebarBottomLeft + sidebarSize; float3 outputColor = 0; float ev = GetEVAtLocation(uv); @@ -308,7 +319,7 @@ Shader "Hidden/HDRP/DebugExposure" { outputColor = ToHeat(evInRange); } - else if (ev > ParamExposureLimitMax) // << TODO_FCC: Ask UX TODO what color scheme is good here. + else if (ev > ParamExposureLimitMax) { outputColor = 1.0f; } @@ -322,14 +333,14 @@ Shader "Hidden/HDRP/DebugExposure" float indicatorEV = GetEVAtLocation(indicatorUV); float indicatorEVRange = (indicatorEV - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - DrawHeatSideBar(uv, sidebarBottomLeft, endPointSidebar, indicatorEVRange, 0.66f, sidebarSize, outputColor); + float extremeMargin = 5 * _ScreenSize.z * _RTHandleScale.x; + DrawHeatSideBar(uv, sidebarBottomLeft, endPointSidebar, indicatorEVRange, 0.66f, sidebarSize, extremeMargin, outputColor); int2 unormCoord = input.positionCS.xy; - float heightLabelBar = (DEBUG_FONT_TEXT_WIDTH * 1.25f) * _ScreenSize.w * _RTHandleScale.y; // Label bar float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy; - if (uv.y + (sidebarSize.y * _RTHandleScale.y) < endPointSidebar.y && + if (uv.y < heightLabelBar && uv.x >= (sidebarBottomLeft.x - borderSize.x) && uv.x <= (borderSize.x + endPointSidebar.x)) { outputColor = outputColor * 0.075f; @@ -340,8 +351,8 @@ Shader "Hidden/HDRP/DebugExposure" float oneOverLabelCount = rcp(labelCount); float labelDeltaScreenSpace = _ScreenSize.x * oneOverLabelCount; - int minLabelLocationX = (sidebarBottomLeft.x - borderSize.x) *_ScreenSize.x + DEBUG_FONT_TEXT_WIDTH * 0.25; - int maxLabelLocationX = (borderSize.x + endPointSidebar.x) *_ScreenSize.x - (DEBUG_FONT_TEXT_WIDTH * 3); + int minLabelLocationX = (sidebarBottomLeft.x - borderSize.x) * (_ScreenSize.x / _RTHandleScale.x) + DEBUG_FONT_TEXT_WIDTH * 0.25; + int maxLabelLocationX = (borderSize.x + endPointSidebar.x) * (_ScreenSize.x / _RTHandleScale.x) - (DEBUG_FONT_TEXT_WIDTH * 3); int labelLocationY = 0.0f; @@ -354,19 +365,10 @@ Shader "Hidden/HDRP/DebugExposure" DrawFloatExplicitPrecision(labelValue, float3(1.0f, 1.0f, 1.0f), unormCoord, 1, labelLoc, outputColor.rgb); } - - //int2 labelEVMinLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), 0); - //int2 textLocation = labelEVMinLoc; - //DrawFloatExplicitPrecision(ParamExposureLimitMin, textColor, unormCoord, 1, textLocation, outputColor.rgb); - //int2 labelEVMaxLoc = (sidebarBottomLeft * _ScreenSize.xy * (1.0f / _RTHandleScale.xy)) + int2(-(sidebarSize.x * _ScreenSize.x + DEBUG_FONT_TEXT_WIDTH), sidebarSize.y * 0.98 * _ScreenSize.y); - //textLocation = labelEVMaxLoc; - //DrawFloatExplicitPrecision(ParamExposureLimitMax, textColor, unormCoord, 1, textLocation, outputColor.rgb); - int displayTextOffsetX = DEBUG_FONT_TEXT_WIDTH; int2 textLocation = int2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); DrawFloatExplicitPrecision(indicatorEV, textColor, unormCoord, 1, textLocation, outputColor.rgb); - return outputColor; } From f5d1d79346da546987c7b2e2ee936128ec2fd397 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 4 May 2020 15:52:37 +0200 Subject: [PATCH 16/27] Add an X at center --- .../Runtime/Debug/DebugExposure.shader | 2 ++ 1 file changed, 2 insertions(+) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 19de857a408..fd488728161 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -368,6 +368,8 @@ Shader "Hidden/HDRP/DebugExposure" int displayTextOffsetX = DEBUG_FONT_TEXT_WIDTH; int2 textLocation = int2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y); DrawFloatExplicitPrecision(indicatorEV, textColor, unormCoord, 1, textLocation, outputColor.rgb); + textLocation = _MousePixelCoord.xy; + DrawCharacter('X', float3(0.0f, 0.0f, 0.0f), unormCoord, textLocation, outputColor.rgb); return outputColor; } From cae8e6e2772ea79f4c7afa4180326a90567b1182 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 4 May 2020 17:43:49 +0200 Subject: [PATCH 17/27] Metering PiP --- .../Runtime/Debug/DebugExposure.shader | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index fd488728161..bc125d58bc9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -7,6 +7,8 @@ Shader "Hidden/HDRP/DebugExposure" #define DEBUG_DISPLAY #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" +#pragma enable_d3d11_debug_symbols + #pragma vertex Vert #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch @@ -284,8 +286,6 @@ Shader "Hidden/HDRP/DebugExposure" } - - float3 FragMetering(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); @@ -293,7 +293,26 @@ Shader "Hidden/HDRP/DebugExposure" float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); - return color * weight; + float pipFraction = 0.33f; + uint borderSize = 3; + float2 topRight = pipFraction * _ScreenSize.xy; + + if (all(input.positionCS.xy < topRight)) + { + float2 scaledUV = uv / pipFraction; + float3 pipColor = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, scaledUV, 0.0).xyz; + float weight = WeightSample(scaledUV.xy * _ScreenSize.xy / _RTHandleScale.xy, _ScreenSize.xy); + + return pipColor * weight; + } + else if (all(input.positionCS.xy < (topRight + borderSize))) + { + return float3(0.33f, 0.33f, 0.33f); + } + else + { + return color; + } } float3 FragSceneEV100(Varyings input) : SV_Target From 2d59944c6e561545b7233aad6b64e379ccecd1c8 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 5 May 2020 13:40:11 +0200 Subject: [PATCH 18/27] Draw tonemap curve and use tonemapped texture for view --- .../Runtime/Debug/DebugDisplay.cs | 39 ++++++++-- .../Runtime/Debug/DebugExposure.shader | 73 ++++++++++++++++++- .../Runtime/Debug/LightingDebug.cs | 2 + .../PostProcessing/PostProcessSystem.cs | 14 +++- .../RenderPipeline/HDRenderPipeline.cs | 46 +++++++++++- .../RenderPipeline/HDStringConstants.cs | 1 + 6 files changed, 163 insertions(+), 12 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 1347a1975f1..a58821b508b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -891,14 +891,43 @@ void RegisterLightingDebug() } }); - lighting.children.Add(new DebugUI.Foldout + var exposureFoldout = new DebugUI.Foldout { displayName = "Exposure ", - children = { - new DebugUI.EnumField { displayName = "Debug Mode", getter = () => (int)data.lightingDebugSettings.exposureDebugMode, setter = value => SetExposureDebugMode((ExposureDebugMode)value), autoEnum = typeof(ExposureDebugMode), onValueChanged = RefreshLightingDebug, getIndex = () => data.exposureDebugModeEnumIndex, setIndex = value => data.exposureDebugModeEnumIndex = value }, - new DebugUI.FloatField { displayName = "Debug Exposure Compensation", getter = () => data.lightingDebugSettings.debugExposure, setter = value => data.lightingDebugSettings.debugExposure = value } + children = + { + new DebugUI.EnumField + { + displayName = "Debug Mode", + getter = () => (int) data.lightingDebugSettings.exposureDebugMode, + setter = value => SetExposureDebugMode((ExposureDebugMode) value), + autoEnum = typeof(ExposureDebugMode), onValueChanged = RefreshLightingDebug, + getIndex = () => data.exposureDebugModeEnumIndex, + setIndex = value => data.exposureDebugModeEnumIndex = value + } } - }); + }; + + if (data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.HistogramView) + { + exposureFoldout.children.Add( + new DebugUI.BoolField() + { + displayName = "Show Tonemap curve", + getter = () => data.lightingDebugSettings.showTonemapCurve, + setter = value => data.lightingDebugSettings.showTonemapCurve = value + }); + } + + exposureFoldout.children.Add( + new DebugUI.FloatField + { + displayName = "Debug Exposure Compensation", + getter = () => data.lightingDebugSettings.debugExposure, + setter = value => data.lightingDebugSettings.debugExposure = value + }); + + lighting.children.Add(exposureFoldout); lighting.children.Add(new DebugUI.EnumField { displayName = "Debug Mode", getter = () => (int)data.lightingDebugSettings.debugLightingMode, setter = value => SetDebugLightingMode((DebugLightingMode)value), autoEnum = typeof(DebugLightingMode), onValueChanged = RefreshLightingDebug, getIndex = () => data.lightingDebugModeEnumIndex, setIndex = value => { data.ResetExclusiveEnumIndices(); data.lightingDebugModeEnumIndex = value; } }); lighting.children.Add(new DebugUI.BitField { displayName = "Hierarchy Debug Mode", getter = () => data.lightingDebugSettings.debugLightFilterMode, setter = value => SetDebugLightFilterMode((DebugLightFilterMode)value), enumType = typeof(DebugLightFilterMode), onValueChanged = RefreshLightingDebug, }); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index bc125d58bc9..8a1bba5edf3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -6,6 +6,9 @@ Shader "Hidden/HDRP/DebugExposure" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl" #define DEBUG_DISPLAY #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #pragma enable_d3d11_debug_symbols @@ -15,6 +18,28 @@ Shader "Hidden/HDRP/DebugExposure" #define PERCENTILE_AS_BARS 0 + // Contains the scene color post-processed (tonemapped etc.) + TEXTURE2D_X(_DebugFullScreenTexture); + + // Tonemap related + TEXTURE3D(_LogLut3D); + SAMPLER(sampler_LogLut3D); + + float4 _ExposureDebugParams; + float4 _LogLut3D_Params; // x: 1 / lut_size, y: lut_size - 1, z: contribution, w: unused + // Custom tonemapping settings + float4 _CustomToneCurve; + float4 _ToeSegmentA; + float4 _ToeSegmentB; + float4 _MidSegmentA; + float4 _MidSegmentB; + float4 _ShoSegmentA; + float4 _ShoSegmentB; + + #define _DrawTonemapCurve _ExposureDebugParams.x + #define _TonemapType _ExposureDebugParams.y + + struct Attributes { uint vertexID : SV_VertexID; @@ -35,6 +60,32 @@ Shader "Hidden/HDRP/DebugExposure" return output; } + float3 Tonemap(float3 colorLinear) + { + if(_TonemapType == 1) // Neutral + { + colorLinear = NeutralTonemap(colorLinear); + } + if (_TonemapType == 2) // ACES + { + // Note: input is actually ACEScg (AP1 w/ linear encoding) + float3 aces = ACEScg_to_ACES(colorLinear); + colorLinear = AcesTonemap(aces); + } + if (_TonemapType == 3) // Custom + { + colorLinear = CustomTonemap(colorLinear, _CustomToneCurve.xyz, _ToeSegmentA, _ToeSegmentB.xy, _MidSegmentA, _MidSegmentB.xy, _ShoSegmentA, _ShoSegmentB.xy); + } + if (_TonemapType == 4) // External + { + float3 colorLutSpace = saturate(LinearToLogC(colorLinear)); + float3 colorLut = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); + colorLinear = lerp(colorLinear, colorLut, _LogLut3D_Params.z); + } + + return colorLinear; + } + float3 ToHeat(float value) { float3 r = value * 2.1f - float3(1.8f, 1.14f, 0.3f); @@ -284,13 +335,31 @@ Shader "Hidden/HDRP/DebugExposure" #endif } + // ---- Draw Tonemap curve ---- + if (_DrawTonemapCurve) + { + float exposureAtLoc = lerp(ParamExposureLimitMin, ParamExposureLimitMax, uv.x); + const float K = 12.5; // Reflected-light meter calibration constant + float luminanceFromExposure = _ExposureTexture[int2(0, 0)].x * (exp2(exposureAtLoc) * (K / 100.0f)); + + val = saturate(Tonemap(luminanceFromExposure)); + val *= 0.95 * (frameHeight - heightLabelBar); + val += heightLabelBar; + + float curveWidth = 4 * _ScreenSize.w; + + if (uv.y < val && uv.y >(val - curveWidth)) + { + outColor = outColor * 0.1 + 0.9 * 0; + } + } } float3 FragMetering(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float2 uv = input.texcoord.xy; - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz; float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); float pipFraction = 0.33f; @@ -400,7 +469,7 @@ Shader "Hidden/HDRP/DebugExposure" UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float2 uv = input.texcoord.xy; - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz; float weight = WeightSample(input.positionCS.xy, _ScreenSize.xy); float3 outputColor = color; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs index 9c41ff778ad..853feb4ada1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -313,6 +313,8 @@ public bool IsDebugDisplayEnabled() public ExposureDebugMode exposureDebugMode = ExposureDebugMode.None; /// Exposure compensation to apply on current scene exposure. public float debugExposure = 0.0f; + /// Whether to show tonemap curve in the histogram debug view or not. + public bool showTonemapCurve = false; /// Display the light cookies atlas. public bool displayCookieAtlas = false; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index 6a5e8d86d51..0b93068f910 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -784,12 +784,22 @@ public RTHandle GetPreviousExposureTexture(HDCamera camera) return rt ?? m_EmptyExposureTexture; } - public RTHandle GetExposureDebugData() + internal RTHandle GetExposureDebugData() { return m_DebugExposureData; } - public ComputeBuffer GetHistogramBuffer() + internal HableCurve GetCustomToneMapCurve() + { + return m_HableCurve; + } + + internal int GetLutSize() + { + return m_LutSize; + } + + internal ComputeBuffer GetHistogramBuffer() { return m_HistogramBuffer; } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index e1e05c9ecb1..ae07e9a06db 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -2485,6 +2485,8 @@ void Callback(CommandBuffer c, HDCamera cam) RenderTargetIdentifier postProcessDest = HDUtils.PostProcessIsFinalPass(hdCamera) ? target.id : m_IntermediateAfterPostProcessBuffer; RenderPostProcess(cullingResults, hdCamera, postProcessDest, renderContext, cmd); + PushFullScreenExposureDebugTexture(cmd, m_IntermediateAfterPostProcessBuffer); + RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterPostProcess, aovRequest, aovCustomPassBuffers); // Copy and rescale depth buffer for XR devices @@ -4279,8 +4281,6 @@ bool NeedsFullScreenDebugMode() void PushFullScreenLightingDebugTexture(HDCamera hdCamera, CommandBuffer cmd, RTHandle textureID) { - // In practice, this is only useful for the SingleShadow debug view. - // TODO: See how we can make this nicer than a specific functions just for one case. if (NeedsFullScreenDebugMode() && m_FullScreenDebugPushed == false) { m_FullScreenDebugPushed = true; @@ -4288,6 +4288,14 @@ void PushFullScreenLightingDebugTexture(HDCamera hdCamera, CommandBuffer cmd, RT } } + void PushFullScreenExposureDebugTexture(CommandBuffer cmd, RTHandle textureID) + { + if (m_CurrentDebugDisplaySettings.data.lightingDebugSettings.exposureDebugMode != ExposureDebugMode.None) + { + HDUtils.BlitCameraTexture(cmd, textureID, m_DebugFullScreenTempBuffer); + } + } + internal void PushFullScreenDebugTexture(HDCamera hdCamera, CommandBuffer cmd, RTHandle textureID, FullScreenDebugMode debugMode) { if (debugMode == m_CurrentDebugDisplaySettings.data.fullScreenDebugMode) @@ -4412,10 +4420,13 @@ static void ResolveColorPickerDebug(in DebugParameters parameters, static void RenderExposureDebug(in DebugParameters parameters, RTHandle inputColorBuffer, + RTHandle postprocessedColorBuffer, RTHandle currentExposure, RTHandle prevExposure, RTHandle debugExposureData, RTHandle output, + HableCurve hableCurve, + int lutSize, ComputeBuffer histogramBuffer, CommandBuffer cmd) { @@ -4439,6 +4450,7 @@ static void RenderExposureDebug(in DebugParameters parameters, parameters.debugExposureMaterial.SetVector(HDShaderIDs._ExposureParams, exposureParams); parameters.debugExposureMaterial.SetVector(HDShaderIDs._MousePixelCoord, HDUtils.GetMouseCoordinates(parameters.hdCamera)); parameters.debugExposureMaterial.SetTexture(HDShaderIDs._SourceTexture, inputColorBuffer); + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._DebugFullScreenTexture, postprocessedColorBuffer); parameters.debugExposureMaterial.SetTexture(HDShaderIDs._PreviousExposureTexture, prevExposure); parameters.debugExposureMaterial.SetTexture(HDShaderIDs._ExposureTexture, currentExposure); parameters.debugExposureMaterial.SetTexture(HDShaderIDs._ExposureWeightMask, exposureSettings.weightTextureMask.value); @@ -4451,6 +4463,33 @@ static void RenderExposureDebug(in DebugParameters parameters, if (parameters.debugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.HistogramView) { parameters.debugExposureMaterial.SetTexture(HDShaderIDs._ExposureDebugTexture, debugExposureData); + var tonemappingSettings = parameters.hdCamera.volumeStack.GetComponent(); + + bool toneMapIsEnabled = parameters.hdCamera.frameSettings.IsEnabled(FrameSettingsField.Tonemapping); + var tonemappingMode = toneMapIsEnabled ? tonemappingSettings.mode.value : TonemappingMode.None; + + bool drawTonemapCurve = tonemappingMode != TonemappingMode.None && + parameters.debugDisplaySettings.data.lightingDebugSettings.showTonemapCurve; + + parameters.debugExposureMaterial.SetVector(HDShaderIDs._ExposureDebugParams, new Vector4(drawTonemapCurve ? 1.0f : 0.0f, (int)tonemappingMode, 0, 0)); + if (drawTonemapCurve) + { + if (tonemappingMode == TonemappingMode.Custom) + { + parameters.debugExposureMaterial.SetVector(HDShaderIDs._CustomToneCurve, hableCurve.uniforms.curve); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._ToeSegmentA, hableCurve.uniforms.toeSegmentA); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._ToeSegmentB, hableCurve.uniforms.toeSegmentB); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._MidSegmentA, hableCurve.uniforms.midSegmentA); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._MidSegmentB, hableCurve.uniforms.midSegmentB); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._ShoSegmentA, hableCurve.uniforms.shoSegmentA); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._ShoSegmentB, hableCurve.uniforms.shoSegmentB); + } + } + else if (tonemappingMode == TonemappingMode.External) + { + parameters.debugExposureMaterial.SetTexture(HDShaderIDs._LogLut3D, tonemappingSettings.lutTexture.value); + parameters.debugExposureMaterial.SetVector(HDShaderIDs._LogLut3D_Params, new Vector4(1f / lutSize, lutSize - 1f, tonemappingSettings.lutContribution.value, 0f)); + } passIndex = 2; } @@ -4501,7 +4540,8 @@ void RenderDebug(HDCamera hdCamera, CommandBuffer cmd, CullingResults cullResult if (debugParams.exposureDebugEnabled) { - RenderExposureDebug(debugParams, m_CameraColorBuffer, m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), m_PostProcessSystem.GetExposureDebugData(),m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetHistogramBuffer(), cmd); + RenderExposureDebug(debugParams, m_CameraColorBuffer, m_DebugFullScreenTempBuffer,m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), + m_PostProcessSystem.GetExposureDebugData(),m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetCustomToneMapCurve(), m_PostProcessSystem.GetLutSize(), m_PostProcessSystem.GetHistogramBuffer(), cmd); } // First resolve color picker diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index b8148d66117..58c8be11377 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -597,6 +597,7 @@ static class HDShaderIDs public static readonly int _PreviousExposureTexture = Shader.PropertyToID("_PreviousExposureTexture"); public static readonly int _ExposureDebugTexture = Shader.PropertyToID("_ExposureDebugTexture"); public static readonly int _ExposureParams = Shader.PropertyToID("_ExposureParams"); + public static readonly int _ExposureDebugParams = Shader.PropertyToID("_ExposureDebugParams"); public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); public static readonly int _HistogramBuffer = Shader.PropertyToID("_HistogramBuffer"); public static readonly int _AdaptationParams = Shader.PropertyToID("_AdaptationParams"); From 7f83e1ae1d820630d6b049d104e861fc1a462684 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 5 May 2020 16:30:47 +0200 Subject: [PATCH 19/27] Share some code --- .../PostProcessing/Components/Exposure.cs | 4 +- .../PostProcessing/PostProcessSystem.cs | 39 +++++++------------ 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs index 5c4e563a776..9560d022997 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs @@ -91,15 +91,13 @@ public sealed class Exposure : VolumeComponent, IPostProcessComponent [Tooltip("Sets the texture mask to be used to weight the pixels in the buffer for the sake of computing exposure.")] public NoInterpTextureParameter weightTextureMask = new NoInterpTextureParameter(null); - // TODO_FCC TODO: DO BEFORE PR. Better name and doc here. - /// /// These values are the lower and upper percentages of the histogram that will be used to /// find a stable average luminance. Values outside of this range will be discarded and won't /// contribute to the average luminance. /// [Tooltip("Sets the range of values (in terms of percentages) of the histogram that are accepted while finding a stable average exposure. Anything outside the value is discarded.")] - public FloatRangeParameter histogramPercentages = new FloatRangeParameter(new Vector2(50.0f, 90.0f), 0.0f, 100.0f); + public FloatRangeParameter histogramPercentages = new FloatRangeParameter(new Vector2(40.0f, 90.0f), 0.0f, 100.0f); /// /// Tells if the effect needs to be rendered or not. diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index 0b93068f910..393dfbfb634 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -470,10 +470,11 @@ void PoolSource(ref RTHandle src, RTHandle dst) if (m_Exposure.mode.value == ExposureMode.AutomaticHistogram) { DoHistogramBasedExposure(cmd, camera, source); - // m_Exposure.mode.value = ExposureMode.Automatic; } else + { DoDynamicExposure(cmd, camera, source); + } // On reset history we need to apply dynamic exposure immediately to avoid // white or black screen flashes when the current exposure isn't anywhere @@ -887,25 +888,7 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) var cs = m_Resources.shaders.exposureCS; int kernel; - GrabExposureHistoryTextures(camera, out var prevExposure, out var nextExposure); - - // Setup variants - var adaptationMode = m_Exposure.adaptationMode.value; - - if (!Application.isPlaying || camera.resetPostProcessingHistory) - adaptationMode = AdaptationMode.Fixed; - - if (camera.resetPostProcessingHistory) - { - // For Dynamic Exposure, we need to undo the pre-exposure from the color buffer to calculate the correct one - // When we reset history we must setup neutral value - prevExposure = m_EmptyExposureTexture; // Use neutral texture - } - - m_ExposureVariants[0] = 1; // (int)exposureSettings.luminanceSource.value; - m_ExposureVariants[1] = (int)m_Exposure.meteringMode.value; - m_ExposureVariants[2] = (int)adaptationMode; - m_ExposureVariants[3] = 0; + DynamicExposureSetup(cmd, camera, out var prevExposure, out var nextExposure); var sourceTex = colorBuffer; @@ -954,13 +937,9 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) cmd.DispatchCompute(cs, kernel, 1, 1, 1); } - void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourceTexture) + void DynamicExposureSetup(CommandBuffer cmd, HDCamera camera, out RTHandle prevExposure, out RTHandle nextExposure) { - var cs = m_Resources.shaders.histogramExposureCS; - cs.shaderKeywords = null; - int kernel; - - GrabExposureHistoryTextures(camera, out var prevExposure, out var nextExposure); + GrabExposureHistoryTextures(camera, out prevExposure, out nextExposure); // Setup variants var adaptationMode = m_Exposure.adaptationMode.value; @@ -980,7 +959,15 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc m_ExposureVariants[1] = (int)m_Exposure.meteringMode.value; m_ExposureVariants[2] = (int)adaptationMode; m_ExposureVariants[3] = 0; + } + + void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourceTexture) + { + var cs = m_Resources.shaders.histogramExposureCS; + cs.shaderKeywords = null; + int kernel; + DynamicExposureSetup(cmd, camera, out var prevExposure, out var nextExposure); // Parameters Vector2 histogramFraction = m_Exposure.histogramPercentages.value / 100.0f; float evRange = m_Exposure.limitMax.value - m_Exposure.limitMin.value; From d002b891b7cf5cfb8b075fe6b8be5fa92fced9af Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 5 May 2020 17:59:34 +0200 Subject: [PATCH 20/27] Curve remapping for histogram and fix some warning --- .../Editor/PostProcessing/ExposureEditor.cs | 8 +++ .../Runtime/Debug/DebugDisplay.hlsl | 1 + .../Runtime/Debug/DebugExposure.shader | 4 +- .../PostProcessing/Components/Exposure.cs | 6 ++ .../PostProcessing/PostProcessSystem.cs | 61 +++++++++++-------- .../PostProcessing/Shaders/Exposure.compute | 4 +- .../Shaders/ExposureCommon.hlsl | 12 +++- .../Shaders/HistogramExposure.compute | 5 ++ .../RenderPipeline/HDStringConstants.cs | 1 + 9 files changed, 70 insertions(+), 32 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs index 3622ceff329..35c7c585bbe 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs @@ -24,6 +24,7 @@ sealed class ExposureEditor : VolumeComponentEditor SerializedDataParameter m_WeightTextureMask; SerializedDataParameter m_HistogramPercentages; + SerializedDataParameter m_HistogramCurveRemapping; public override void OnEnable() { @@ -46,6 +47,8 @@ public override void OnEnable() m_WeightTextureMask = Unpack(o.Find(x => x.weightTextureMask)); m_HistogramPercentages = Unpack(o.Find(x => x.histogramPercentages)); + m_HistogramCurveRemapping = Unpack(o.Find(x => x.histogramUseCurveRemapping)); + } public override void OnInspectorGUI() @@ -88,6 +91,11 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); EditorGUILayout.LabelField("Histogram", EditorStyles.miniLabel); PropertyField(m_HistogramPercentages); + PropertyField(m_HistogramCurveRemapping, EditorGUIUtility.TrTextContent("Use Curve Remapping")); + if (m_HistogramCurveRemapping.value.boolValue) + { + PropertyField(m_CurveMap); + } } EditorGUILayout.Space(); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl index f7e7033b683..1ed2109002a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl @@ -180,6 +180,7 @@ void DrawInteger(int intValue, float3 fontColor, uint2 currentUnormCoord, inout fixedUnormCoord.x += numEntries * DEBUG_FONT_TEXT_SCALE_WIDTH; // 3. Display the number + [unroll] // Needed to supress warning as some odd code gen is happening here. Is bad for perf, but it is a debug display. for (uint j = 0; j < maxStringSize; ++j) { // Numeric value incurrent font start on the second row at 0 diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 8a1bba5edf3..15a929d2568 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -318,7 +318,7 @@ Shader "Hidden/HDRP/DebugExposure" float evInRange = (currExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); float targetEVInRange = (targetExposure - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin); - float2 halfIndicatorSize = 0.007f; + float halfIndicatorSize = 0.007f; float halfWidthInScreen = halfIndicatorSize * _ScreenSize.x; float labelFrameHeightScreen = heightLabelBar * (_ScreenSize.y / _RTHandleScale.y); @@ -342,7 +342,7 @@ Shader "Hidden/HDRP/DebugExposure" const float K = 12.5; // Reflected-light meter calibration constant float luminanceFromExposure = _ExposureTexture[int2(0, 0)].x * (exp2(exposureAtLoc) * (K / 100.0f)); - val = saturate(Tonemap(luminanceFromExposure)); + val = saturate(Luminance(Tonemap(luminanceFromExposure))); val *= 0.95 * (frameHeight - heightLabelBar); val += heightLabelBar; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs index 9560d022997..7c942954e1e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Exposure.cs @@ -99,6 +99,12 @@ public sealed class Exposure : VolumeComponent, IPostProcessComponent [Tooltip("Sets the range of values (in terms of percentages) of the histogram that are accepted while finding a stable average exposure. Anything outside the value is discarded.")] public FloatRangeParameter histogramPercentages = new FloatRangeParameter(new Vector2(40.0f, 90.0f), 0.0f, 100.0f); + /// + /// Sets whether histogram exposure mode will remap the computed exposure with a curve remapping (akin to Curve Remapping mode) + /// + [Tooltip("Sets whether histogram exposure mode will remap the computed exposure with a curve remapping (akin to Curve Remapping mode).")] + public BoolParameter histogramUseCurveRemapping = new BoolParameter(false); + /// /// Tells if the effect needs to be rendered or not. /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index 393dfbfb634..11f7fb7dac7 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -883,6 +883,29 @@ void PrepareExposureCurveData(AnimationCurve curve, out float min, out float max m_ExposureCurveTexture.Apply(); } + void DynamicExposureSetup(CommandBuffer cmd, HDCamera camera, out RTHandle prevExposure, out RTHandle nextExposure) + { + GrabExposureHistoryTextures(camera, out prevExposure, out nextExposure); + + // Setup variants + var adaptationMode = m_Exposure.adaptationMode.value; + + if (!Application.isPlaying || camera.resetPostProcessingHistory) + adaptationMode = AdaptationMode.Fixed; + + if (camera.resetPostProcessingHistory) + { + // For Dynamic Exposure, we need to undo the pre-exposure from the color buffer to calculate the correct one + // When we reset history we must setup neutral value + prevExposure = m_EmptyExposureTexture; // Use neutral texture + } + + m_ExposureVariants[0] = 1; // (int)exposureSettings.luminanceSource.value; + m_ExposureVariants[1] = (int)m_Exposure.meteringMode.value; + m_ExposureVariants[2] = (int)adaptationMode; + m_ExposureVariants[3] = 0; + } + void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) { var cs = m_Resources.shaders.exposureCS; @@ -926,6 +949,8 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) PrepareExposureCurveData(m_Exposure.curveMap.value, out float min, out float max); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureCurveTexture, m_ExposureCurveTexture); cmd.SetComputeVectorParam(cs, HDShaderIDs._ExposureParams, new Vector4(m_Exposure.compensation.value + m_DebugExposureCompensation, min, max, 0f)); + cmd.SetComputeVectorParam(cs, HDShaderIDs._ExposureParams2, new Vector4(min, max, 0f, 0f)); + m_ExposureVariants[3] = 2; } @@ -937,30 +962,6 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer) cmd.DispatchCompute(cs, kernel, 1, 1, 1); } - void DynamicExposureSetup(CommandBuffer cmd, HDCamera camera, out RTHandle prevExposure, out RTHandle nextExposure) - { - GrabExposureHistoryTextures(camera, out prevExposure, out nextExposure); - - // Setup variants - var adaptationMode = m_Exposure.adaptationMode.value; - - if (!Application.isPlaying || camera.resetPostProcessingHistory) - adaptationMode = AdaptationMode.Fixed; - - if (camera.resetPostProcessingHistory) - { - // For Dynamic Exposure, we need to undo the pre-exposure from the color buffer to calculate the correct one - // When we reset history we must setup neutral value - prevExposure = m_EmptyExposureTexture; // Use neutral texture - } - - // TODO_FCC TODO: Make this generic setup in a function so that we can share with dynamic exposure. - m_ExposureVariants[0] = 1; // (int)exposureSettings.luminanceSource.value; - m_ExposureVariants[1] = (int)m_Exposure.meteringMode.value; - m_ExposureVariants[2] = (int)adaptationMode; - m_ExposureVariants[3] = 0; - } - void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourceTexture) { var cs = m_Resources.shaders.histogramExposureCS; @@ -981,7 +982,6 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc // Generate histogram. kernel = cs.FindKernel("KHistogramGen"); - cmd.SetComputeIntParams(cs, HDShaderIDs._Variants, m_ExposureVariants); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._SourceTexture, sourceTexture); if (m_Exposure.meteringMode == MeteringMode.MaskWeighted && m_Exposure.weightTextureMask.value != null) @@ -993,6 +993,8 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureWeightMask, Texture2D.whiteTexture); } + cmd.SetComputeIntParams(cs, HDShaderIDs._Variants, m_ExposureVariants); + cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs._HistogramBuffer, m_HistogramBuffer); int threadGroupSizeX = 16; @@ -1010,6 +1012,15 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._OutputTexture, nextExposure); + if (m_Exposure.histogramUseCurveRemapping.value) + { + PrepareExposureCurveData(m_Exposure.curveMap.value, out float min, out float max); + cmd.SetComputeVectorParam(cs, HDShaderIDs._ExposureParams2, new Vector4(min, max, 0f, 0f)); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureCurveTexture, m_ExposureCurveTexture); + m_ExposureVariants[3] = 2; + } + cmd.SetComputeIntParams(cs, HDShaderIDs._Variants, m_ExposureVariants); + if (m_HDInstance.m_CurrentDebugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.HistogramView) { cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureDebugTexture, m_DebugExposureData); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute index aff1cc70e65..b2aec7d232e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute @@ -8,7 +8,6 @@ #pragma kernel KReduction #pragma kernel KReset -TEXTURE2D(_ExposureCurveTexture); TEXTURE2D(_InputTexture); #define PREPASS_TEX_SIZE 1024.0 @@ -128,8 +127,7 @@ void KReduction(uint2 groupId : SV_GroupID, uint2 groupThreadId : SV_GroupThread case 2u: { // Curve remapping - float remap = saturate((avgLuminance - ParamCurveMin) / (ParamCurveMax - ParamCurveMin)); - float exposure = SAMPLE_TEXTURE2D_LOD(_ExposureCurveTexture, s_linear_clamp_sampler, float2(remap, 0.0), 0.0).x; + float exposure = CurveRemap(avgLuminance); exposure = AdaptExposure(exposure - ParamExposureCompensation); _OutputTexture[groupId.xy] = float2(ConvertEV100ToExposure(exposure), exposure); break; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl index 28a9cdad9f7..f12efaea4f9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl @@ -8,9 +8,11 @@ TEXTURE2D(_ExposureWeightMask); TEXTURE2D_X(_SourceTexture); TEXTURE2D(_PreviousExposureTexture); RW_TEXTURE2D(float2, _OutputTexture); +TEXTURE2D(_ExposureCurveTexture); CBUFFER_START(cb) float4 _ExposureParams; +float4 _ExposureParams2; float4 _HistogramExposureParams; float4 _AdaptationParams; uint4 _Variants; @@ -25,8 +27,8 @@ CBUFFER_END #define ParamSpeedDarkToLight _AdaptationParams.y #define ParamExposureLimitMin _ExposureParams.y #define ParamExposureLimitMax _ExposureParams.z -#define ParamCurveMin _ExposureParams.y -#define ParamCurveMax _ExposureParams.z +#define ParamCurveMin _ExposureParams2.x +#define ParamCurveMax _ExposureParams2.y #define ParamSourceBuffer _Variants.x #define ParamMeteringMode _Variants.y #define ParamAdaptationMode _Variants.z @@ -98,3 +100,9 @@ float AdaptExposure(float exposure) return exposure; } } + +float CurveRemap(float inEV) +{ + float remap = saturate((inEV - ParamCurveMin) / (ParamCurveMax - ParamCurveMin)); + return SAMPLE_TEXTURE2D_LOD(_ExposureCurveTexture, s_linear_clamp_sampler, float2(remap, 0.0), 0.0).x; +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index 40cc104e06e..d936b7883f6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -170,6 +170,11 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) w = max(w, 1e-4f); float avgEV = evProcessedSum * rcp(w); + if (ParamEvaluateMode == 2) + { + avgEV = CurveRemap(avgEV); + } + float exposure = AdaptExposure(avgEV - ParamExposureCompensation); exposure = clamp(exposure, ParamExposureLimitMin, ParamExposureLimitMax); _OutputTexture[uint2(0, 0)] = float2(ConvertEV100ToExposure(exposure), exposure); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index 58c8be11377..f4d091189ca 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -597,6 +597,7 @@ static class HDShaderIDs public static readonly int _PreviousExposureTexture = Shader.PropertyToID("_PreviousExposureTexture"); public static readonly int _ExposureDebugTexture = Shader.PropertyToID("_ExposureDebugTexture"); public static readonly int _ExposureParams = Shader.PropertyToID("_ExposureParams"); + public static readonly int _ExposureParams2 = Shader.PropertyToID("_ExposureParams2"); public static readonly int _ExposureDebugParams = Shader.PropertyToID("_ExposureDebugParams"); public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); public static readonly int _HistogramBuffer = Shader.PropertyToID("_HistogramBuffer"); From 9187bbba70332a97c99db914715b606ba4def3ce Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 5 May 2020 18:22:38 +0200 Subject: [PATCH 21/27] Some comments fixup --- .../Runtime/Debug/DebugExposure.shader | 2 -- .../Runtime/PostProcessing/Shaders/HistogramExposure.compute | 5 +---- .../PostProcessing/Shaders/HistogramExposureCommon.hlsl | 2 +- .../Runtime/RenderPipeline/HDRenderPipeline.cs | 2 ++ 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 15a929d2568..37f3779fda2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -10,8 +10,6 @@ Shader "Hidden/HDRP/DebugExposure" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" -#pragma enable_d3d11_debug_symbols - #pragma vertex Vert #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index d936b7883f6..d499d286a66 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -3,9 +3,7 @@ // TODO List to investigate -// - Number of bins: // - Worth considering multiple histograms per lane in the thread. (i.e. sharedHisto[BINS][NUMB_HIST] ) -// - Worth checking the optimal group size. // - At the moment the dispatch is at half res, but the buffer sampled is full res, // causing fairly bad cache behaviour. Can we use the mip chain realistically without issues? [The one we have is blurred and might be incomplete?] @@ -155,8 +153,7 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) float2 extremesSums = float2(_HistogramMinPercentile, _HistogramMaxPercentile) * sum; - // TODO: This can probably done more efficiently. Also verify that all but the first wave - // actually skip this or if we need to enforce it somehow. + // TODO: This can probably done more efficiently. if (threadID == 0) { float evProcessedSum = 0; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl index e1abfe6a5cb..7620df3ec91 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl @@ -1,5 +1,5 @@ -#define HISTOGRAM_BINS 128 // IMPORTANT: If this number is changed, the code needs adapting, I tried to add relevant comments to indicate where. +#define HISTOGRAM_BINS 128 #define _HistogramRangeScale _HistogramExposureParams.x #define _HistogramRangeBias _HistogramExposureParams.y diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index ae07e9a06db..6698265aae4 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4281,6 +4281,8 @@ bool NeedsFullScreenDebugMode() void PushFullScreenLightingDebugTexture(HDCamera hdCamera, CommandBuffer cmd, RTHandle textureID) { + // In practice, this is only useful for the SingleShadow debug view. + // TODO: See how we can make this nicer than a specific functions just for one case. if (NeedsFullScreenDebugMode() && m_FullScreenDebugPushed == false) { m_FullScreenDebugPushed = true; From beb9b399e688e134f6de926e9e7c03fea9f5fc8c Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 May 2020 09:09:24 +0200 Subject: [PATCH 22/27] Simple comment changes --- .../Runtime/Debug/DebugExposure.shader | 2 ++ .../Runtime/Debug/LightingDebug.cs | 2 +- .../Runtime/PostProcessing/PostProcessSystem.cs | 3 ++- .../Runtime/PostProcessing/Shaders/HistogramExposure.compute | 3 +-- .../Runtime/RenderPipeline/HDRenderPipeline.cs | 2 -- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 37f3779fda2..15a929d2568 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -10,6 +10,8 @@ Shader "Hidden/HDRP/DebugExposure" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" +#pragma enable_d3d11_debug_symbols + #pragma vertex Vert #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs index 853feb4ada1..3b6871d6b56 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -314,7 +314,7 @@ public bool IsDebugDisplayEnabled() /// Exposure compensation to apply on current scene exposure. public float debugExposure = 0.0f; /// Whether to show tonemap curve in the histogram debug view or not. - public bool showTonemapCurve = false; + public bool showTonemapCurve = true; /// Display the light cookies atlas. public bool displayCookieAtlas = false; diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index 11f7fb7dac7..557f89b5686 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -1012,11 +1012,12 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._PreviousExposureTexture, prevExposure); cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._OutputTexture, nextExposure); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureCurveTexture, m_ExposureCurveTexture); + m_ExposureVariants[3] = 0; if (m_Exposure.histogramUseCurveRemapping.value) { PrepareExposureCurveData(m_Exposure.curveMap.value, out float min, out float max); cmd.SetComputeVectorParam(cs, HDShaderIDs._ExposureParams2, new Vector4(min, max, 0f, 0f)); - cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._ExposureCurveTexture, m_ExposureCurveTexture); m_ExposureVariants[3] = 2; } cmd.SetComputeIntParams(cs, HDShaderIDs._Variants, m_ExposureVariants); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute index d499d286a66..43e5ccbdc54 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposure.compute @@ -51,7 +51,6 @@ void KHistogramGen(uint groupIndex : SV_GroupIndex, InterlockedAdd(gs_localHistogram[bin], PackWeight(weight)); } - GroupMemoryBarrierWithGroupSync(); // Note that currently the branch is always true (GROUP_SIZE_X * GROUP_SIZE_Y == HISTOGRAM_BINS). Here as safeguard if changing group size or bins. @@ -153,7 +152,7 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID) float2 extremesSums = float2(_HistogramMinPercentile, _HistogramMaxPercentile) * sum; - // TODO: This can probably done more efficiently. + // TODO: Can we be a bit more parallel here? if (threadID == 0) { float evProcessedSum = 0; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 6698265aae4..41879de5978 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4432,8 +4432,6 @@ static void RenderExposureDebug(in DebugParameters parameters, ComputeBuffer histogramBuffer, CommandBuffer cmd) { - - //parameters.exposureMaterial.set // Grab exposure parameters var exposureSettings = parameters.hdCamera.volumeStack.GetComponent(); From 9f7ee5fd69fa3c7e73127a8311af38bdad42af85 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 May 2020 09:54:05 +0200 Subject: [PATCH 23/27] Revert debug symbol in shader --- .../Runtime/Debug/DebugExposure.shader | 2 -- 1 file changed, 2 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 15a929d2568..37f3779fda2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -10,8 +10,6 @@ Shader "Hidden/HDRP/DebugExposure" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" -#pragma enable_d3d11_debug_symbols - #pragma vertex Vert #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone vulkan metal switch From a544903e9bd0bf8f67b74973647640f12906a9f0 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 May 2020 09:56:59 +0200 Subject: [PATCH 24/27] Changelog --- com.unity.render-pipelines.high-definition/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 7199a81536c..798fefa1470 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -112,6 +112,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added a ray tracing mode option in the HDRP asset that allows to override and shader stripping. - Added support for arbitrary resolution scaling of Volumetric Lighting to the Fog volume component. - Added range attenuation for box-shaped spotlights. +- Added Histogram guided automatic exposure. +- Added few exposure debug modes. ### Fixed - Fix when rescale probe all direction below zero (1219246) From 12632b6ad4b5e6674f44dd41bc5752c565885150 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 May 2020 16:19:58 +0200 Subject: [PATCH 25/27] review fixups --- .../Runtime/Debug/DebugExposure.shader | 15 ++++++--------- .../Runtime/Debug/LightingDebug.cs.hlsl | 8 ++++++++ .../PostProcessing/Components/Tonemapping.cs | 1 + .../Components/Tonemapping.cs.hlsl | 17 +++++++++++++++++ .../Components/Tonemapping.cs.hlsl.meta | 10 ++++++++++ .../PostProcessing/Shaders/Exposure.compute | 1 - 6 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader index 37f3779fda2..bdd95e18d60 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugExposure.shader @@ -2,6 +2,7 @@ Shader "Hidden/HDRP/DebugExposure" { HLSLINCLUDE + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/ExposureCommon.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HistogramExposureCommon.hlsl" #define DEBUG_DISPLAY @@ -60,21 +61,21 @@ Shader "Hidden/HDRP/DebugExposure" float3 Tonemap(float3 colorLinear) { - if(_TonemapType == 1) // Neutral + if(_TonemapType == TONEMAPPINGMODE_NEUTRAL) { colorLinear = NeutralTonemap(colorLinear); } - if (_TonemapType == 2) // ACES + if (_TonemapType == TONEMAPPINGMODE_ACES) { // Note: input is actually ACEScg (AP1 w/ linear encoding) float3 aces = ACEScg_to_ACES(colorLinear); colorLinear = AcesTonemap(aces); } - if (_TonemapType == 3) // Custom + if (_TonemapType == TONEMAPPINGMODE_CUSTOM) // Custom { colorLinear = CustomTonemap(colorLinear, _CustomToneCurve.xyz, _ToeSegmentA, _ToeSegmentB.xy, _MidSegmentA, _MidSegmentB.xy, _ShoSegmentA, _ShoSegmentB.xy); } - if (_TonemapType == 4) // External + if (_TonemapType == TONEMAPPINGMODE_EXTERNAL) // External { float3 colorLutSpace = saturate(LinearToLogC(colorLinear)); float3 colorLut = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); @@ -92,11 +93,7 @@ Shader "Hidden/HDRP/DebugExposure" float GetEVAtLocation(float2 uv) { - float3 color = SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, uv, 0.0).xyz; - float prevExposure = ConvertEV100ToExposure(GetPreviousExposureEV100()); - float luma = Luminance(color / prevExposure); - - return ComputeEV100FromAvgLuminance(max(luma, 1e-4)); + return ComputeEV100FromAvgLuminance(max(SampleLuminance(uv), 1e-4)); } // Returns true if it drew the location of the indicator. diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl index 28338f1bab5..bc46e7e5126 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl @@ -62,6 +62,14 @@ #define SHADOWMAPDEBUGMODE_VISUALIZE_SHADOW_MAP (4) #define SHADOWMAPDEBUGMODE_SINGLE_SHADOW (5) +// +// UnityEngine.Rendering.HighDefinition.ExposureDebugMode: static fields +// +#define EXPOSUREDEBUGMODE_NONE (0) +#define EXPOSUREDEBUGMODE_SCENE_EV100VALUES (1) +#define EXPOSUREDEBUGMODE_HISTOGRAM_VIEW (2) +#define EXPOSUREDEBUGMODE_METERING_WEIGHTED (3) + // // UnityEngine.Rendering.HighDefinition.ProbeVolumeDebugMode: static fields // diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs index b103590431d..ef60f9e25e3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs @@ -6,6 +6,7 @@ namespace UnityEngine.Rendering.HighDefinition /// Available tonemapping modes. /// /// + [GenerateHLSL] public enum TonemappingMode { /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl new file mode 100644 index 00000000000..01a14dbe92d --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl @@ -0,0 +1,17 @@ +// +// This file was automatically generated. Please don't edit by hand. +// + +#ifndef TONEMAPPING_CS_HLSL +#define TONEMAPPING_CS_HLSL +// +// UnityEngine.Rendering.HighDefinition.TonemappingMode: static fields +// +#define TONEMAPPINGMODE_NONE (0) +#define TONEMAPPINGMODE_NEUTRAL (1) +#define TONEMAPPINGMODE_ACES (2) +#define TONEMAPPINGMODE_CUSTOM (3) +#define TONEMAPPINGMODE_EXTERNAL (4) + + +#endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl.meta new file mode 100644 index 00000000000..dbc46634e4a --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3716aaa9cab64e5419f00d48a69fab04 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute index b2aec7d232e..4e53910f142 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/Exposure.compute @@ -12,7 +12,6 @@ TEXTURE2D(_InputTexture); #define PREPASS_TEX_SIZE 1024.0 #define PREPASS_TEX_HALF_SIZE 512.0 -#pragma enable_d3d11_debug_symbols // // Fixed exposure From e3bab83f6b3e6632e987ca0a3316f91fbf2b1e9a Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 11 May 2020 13:06:00 +0200 Subject: [PATCH 26/27] Review feedback --- .../Runtime/Debug/DebugDisplay.cs | 4 ++-- .../Runtime/Debug/LightingDebug.cs | 2 +- .../Runtime/RenderPipeline/HDRenderPipeline.Debug.cs | 8 ++++++++ .../Runtime/RenderPipeline/HDRenderPipeline.cs | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index a3e86f6603a..cece56a186e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -914,8 +914,8 @@ void RegisterLightingDebug() new DebugUI.BoolField() { displayName = "Show Tonemap curve", - getter = () => data.lightingDebugSettings.showTonemapCurve, - setter = value => data.lightingDebugSettings.showTonemapCurve = value + getter = () => data.lightingDebugSettings.showTonemapCurveAlongHistogramView, + setter = value => data.lightingDebugSettings.showTonemapCurveAlongHistogramView = value }); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs index 3b6871d6b56..846455a2694 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -314,7 +314,7 @@ public bool IsDebugDisplayEnabled() /// Exposure compensation to apply on current scene exposure. public float debugExposure = 0.0f; /// Whether to show tonemap curve in the histogram debug view or not. - public bool showTonemapCurve = true; + public bool showTonemapCurveAlongHistogramView = true; /// Display the light cookies atlas. public bool displayCookieAtlas = false; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs index 8eda7f371ca..f2854f8ae55 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs @@ -194,6 +194,14 @@ TextureHandle RenderDebug( RenderGraph renderGraph, m_FullScreenDebugPushed = false; } + // TODO RENDERGRAPH (Needs post processing in Rendergraph to properly be implemented) + if(debugParameters.exposureDebugEnabled) + { + // For reference the following is what is called in the non-render-graph version. + // RenderExposureDebug(debugParams, m_CameraColorBuffer, m_DebugFullScreenTempBuffer,m_PostProcessSystem.GetPreviousExposureTexture(hdCamera), m_PostProcessSystem.GetExposureTexture(hdCamera), + // m_PostProcessSystem.GetExposureDebugData(),m_IntermediateAfterPostProcessBuffer, m_PostProcessSystem.GetCustomToneMapCurve(), m_PostProcessSystem.GetLutSize(), m_PostProcessSystem.GetHistogramBuffer(), cmd); + } + if (debugParameters.colorPickerEnabled) output = ResolveColorPickerDebug(renderGraph, debugParameters, colorPickerDebugTexture); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index cc2c3e307af..8a6d2d35f56 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -4531,7 +4531,7 @@ static void RenderExposureDebug(in DebugParameters parameters, var tonemappingMode = toneMapIsEnabled ? tonemappingSettings.mode.value : TonemappingMode.None; bool drawTonemapCurve = tonemappingMode != TonemappingMode.None && - parameters.debugDisplaySettings.data.lightingDebugSettings.showTonemapCurve; + parameters.debugDisplaySettings.data.lightingDebugSettings.showTonemapCurveAlongHistogramView; parameters.debugExposureMaterial.SetVector(HDShaderIDs._ExposureDebugParams, new Vector4(drawTonemapCurve ? 1.0f : 0.0f, (int)tonemappingMode, 0, 0)); if (drawTonemapCurve) From 721950c35996c7239d4a27aaf7faae55c491825a Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 22 May 2020 17:20:50 +0200 Subject: [PATCH 27/27] Bad merge fixup --- .../Runtime/PostProcessing/PostProcessSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs index dbd6fad6d54..0c49a739c0a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs @@ -300,7 +300,6 @@ public void CleanupNonRenderGraphResources() RTHandles.Release(m_TempTexture1024); RTHandles.Release(m_TempTexture32); RTHandles.Release(m_AlphaTexture); - CoreUtils.Destroy(m_InternalSpectralLut); RTHandles.Release(m_InternalLogLut); m_EmptyExposureTexture = null;