2021-09-09 20:42:29 -04:00

812 lines
32 KiB
GLSL

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/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 vertex Vert
#pragma target 4.5
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#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
#define _CenterAroundTargetExposure _ExposureDebugParams.z
#define _FinalImageHistogramRGB _ExposureDebugParams.w
struct Attributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.texcoord = GetNormalizedFullScreenTriangleTexCoord(input.vertexID);
return output;
}
float3 Tonemap(float3 colorLinear)
{
if(_TonemapType == TONEMAPPINGMODE_NEUTRAL)
{
colorLinear = NeutralTonemap(colorLinear);
}
if (_TonemapType == TONEMAPPINGMODE_ACES)
{
// Note: input is actually ACEScg (AP1 w/ linear encoding)
float3 aces = ACEScg_to_ACES(colorLinear);
colorLinear = AcesTonemap(aces);
}
if (_TonemapType == TONEMAPPINGMODE_CUSTOM) // Custom
{
colorLinear = CustomTonemap(colorLinear, _CustomToneCurve.xyz, _ToeSegmentA, _ToeSegmentB.xy, _MidSegmentA, _MidSegmentB.xy, _ShoSegmentA, _ShoSegmentB.xy);
}
if (_TonemapType == TONEMAPPINGMODE_EXTERNAL) // 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);
return 1.0f - r * r;
}
float GetEVAtLocation(float2 uv)
{
return ComputeEV100FromAvgLuminance(max(SampleLuminance(uv), 1e-4), MeterCalibrationConstant);
}
// Returns true if it drew the location of the indicator.
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);
evValueRange = clamp(evValueRange, 0.0f, 1.0f);
int distanceInPixels = abs(evValueRange - inRange) * sidebarSize.x * _ScreenSize.x / _RTHandleScale.x;
if (distanceInPixels < indicatorHalfSize)
{
sidebarColor = indicatorColor;
}
else if (distanceInPixels < indicatorHalfSize + 1)
{
sidebarColor = 0.0f;
}
else
{
sidebarColor = ToHeat(inRange);
}
}
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;
}
}
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)]);
}
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(float 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 DrawTriangleIndicator(float2 coord, float labelBarHeight, float uvXLocation, float widthNDC, float3 color, inout float3 outColor)
{
float halfWidthInScreen = widthNDC * _ScreenSize.x;
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;
uint triangleBorder = 2;
if (coord.x > minScreenPos && coord.x < maxScreenPos && coord.y >= arrowStart)
{
outColor = color;
}
else if (coord.x > minScreenPos - triangleBorder && coord.x < maxScreenPos + triangleBorder && coord.y > arrowStart - triangleBorder)
{
outColor = 0;
}
}
bool DrawEmptyFrame(float2 uv, float3 frameColor, float frameAlpha, float frameHeight, float heightLabelBar, inout float3 outColor)
{
float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy;
if (uv.y > frameHeight) return false;
// ---- Draw General frame ----
if (uv.x < borderSize.x || uv.x >(1.0f - borderSize.x))
{
outColor = 0.0;
return false;
}
else if (uv.y > frameHeight - borderSize.y)
{
outColor = 0.0;
return false;
}
else
{
outColor = lerp(outColor, frameColor, frameAlpha);
}
// ---- Draw label bar -----
if (uv.y < heightLabelBar)
{
outColor = outColor * 0.075f;
}
return true;
}
float2 GetMinMaxLabelRange(float currEV)
{
if (_CenterAroundTargetExposure > 0)
{
int maxAtBothSide = min(0.5f * (ParamExposureLimitMax - ParamExposureLimitMin), 10);
return float2(currEV - maxAtBothSide, currEV + maxAtBothSide);
}
else
{
return float2(ParamExposureLimitMin, ParamExposureLimitMax);
}
}
float EvToUVLocation(float ev, float currEV)
{
float2 valuesRange = GetMinMaxLabelRange(currEV);
return (ev - valuesRange.x) / (valuesRange.y - valuesRange.x);
}
float GetHistogramInfo(float coordOnX, float maxHistValue, float heightLabelBar, float frameHeight, float currExposure, out uint binIndex, out bool isEdgeOfBin)
{
float barSize = _ScreenSize.x / HISTOGRAM_BINS;
float locWithinBin = 0.0f;
if (_CenterAroundTargetExposure > 0)
{
// This is going to be the center of the histogram view in this mode.
uint centerBin = EVToBinLocation(currExposure);
uint midXPoint = _ScreenSize.x / 2;
uint halfBarSize = barSize / 2;
uint lowerMidPoint = midXPoint - halfBarSize;
uint higherMidPoint = midXPoint + halfBarSize;
if (coordOnX < float(lowerMidPoint))
{
uint distanceFromCenter = lowerMidPoint - coordOnX;
float deltaBinFloat = distanceFromCenter / barSize;
uint deltaInBins = ceil(deltaBinFloat);
locWithinBin = frac(deltaBinFloat) * barSize;
binIndex = centerBin - deltaInBins;
}
else if (coordOnX > float(higherMidPoint))
{
uint distanceFromCenter = coordOnX - higherMidPoint;
float deltaBinFloat = distanceFromCenter / barSize;
uint deltaInBins = ceil(deltaBinFloat);
locWithinBin = frac(deltaBinFloat) * barSize;
binIndex = centerBin + deltaInBins;
}
else
{
binIndex = centerBin;
locWithinBin = (higherMidPoint - coordOnX);
}
}
else
{
float bin = coordOnX / barSize;
locWithinBin = barSize * frac(bin);
binIndex = uint(bin);
}
isEdgeOfBin = locWithinBin < 1 || locWithinBin >(barSize - 1);
float val = UnpackWeight(_HistogramBuffer[binIndex]);
val /= maxHistValue;
val *= 0.95*(frameHeight - heightLabelBar);
val += heightLabelBar;
return val;
}
float GetLabel(float labelCount, float labelIdx, float currExposure, out uint2 labelLoc)
{
int minLabelLocationX = DEBUG_FONT_TEXT_WIDTH * 0.25;
int maxLabelLocationX = _ScreenSize.x - (DEBUG_FONT_TEXT_WIDTH * 3);
int labelLocationY = 0.0f;
float2 labelValuesRange = GetMinMaxLabelRange(currExposure);
float t = rcp(labelCount) * (labelIdx - 0.25);
labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY);
return lerp(labelValuesRange.x, labelValuesRange.y, t);
}
float GetTonemappedValueAtLocation(float uvX, float currExposure)
{
float exposureAtLoc = 0;
float2 labelValuesRange = GetMinMaxLabelRange(currExposure);
exposureAtLoc = lerp(labelValuesRange.x, labelValuesRange.y, uvX);
const float K = 12.5; // Reflected-light meter calibration constant
float luminanceFromExposure = _ExposureTexture[int2(0, 0)].x * (exp2(exposureAtLoc) * (K / 100.0f));
return saturate(Luminance(Tonemap(luminanceFromExposure)));
}
void DrawHistogramFrame(float2 uv, uint2 unormCoord, float frameHeight, float3 backgroundColor, float alpha, float maxHist, float minPercentLoc, float maxPercentLoc, inout float3 outColor)
{
float heightLabelBar = (DEBUG_FONT_TEXT_WIDTH * 1.25) * _ScreenSize.w * _RTHandleScale.y;
if (DrawEmptyFrame(uv, backgroundColor, alpha, frameHeight, heightLabelBar, outColor))
{
float currExposure = _ExposureTexture[int2(0, 0)].y;
float targetExposure = _ExposureDebugTexture[int2(0, 0)].x;
// ---- Draw Buckets ----
bool isEdgeOfBin = false;
float val = GetHistogramValue(unormCoord.x, isEdgeOfBin);
val /= maxHist;
val *= 0.95*(frameHeight - heightLabelBar);
val += heightLabelBar;
uint bin = 0;
val = GetHistogramInfo(unormCoord.x, maxHist, heightLabelBar, frameHeight, currExposure, bin, isEdgeOfBin);
if (uv.y < val && uv.y > heightLabelBar)
{
isEdgeOfBin = isEdgeOfBin || (uv.y > val - _ScreenSize.w);
if (bin < uint(minPercentLoc) && minPercentLoc > 0)
{
outColor.rgb = float3(0, 0, 1);
}
else if (bin >= uint(maxPercentLoc) && maxPercentLoc > 0)
{
outColor.rgb = float3(1, 0, 0);
}
else
outColor.rgb = float3(1.0f, 1.0f, 1.0f);
if (isEdgeOfBin) outColor.rgb = 0;
}
// ---- Draw labels ----
// Number of labels
int labelCount = 12;
[unroll]
for (int i = 0; i <= labelCount; ++i)
{
uint2 labelLoc;
float labelValue = GetLabel(labelCount, i, currExposure, labelLoc);
DrawFloatExplicitPrecision(labelValue, float3(1.0f, 1.0f, 1.0f), unormCoord, 1, labelLoc, outColor.rgb);
}
// ---- Draw indicators ----
float evInRange = EvToUVLocation(currExposure, currExposure);
float targetEVInRange = EvToUVLocation(targetExposure, currExposure);
float halfIndicatorSize = 0.007f;
float halfWidthInScreen = halfIndicatorSize * _ScreenSize.x;
float labelFrameHeightScreen = heightLabelBar * (_ScreenSize.y / _RTHandleScale.y);
if (uv.y < heightLabelBar)
{
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);
}
// TODO: Add bar?
//else
//{
// if (_CenterAroundTargetExposure > 0)
// {
// DrawHistogramIndicatorBar(float(unormCoord.x), evInRange, 0.003f, float3(0.0f, 0.0f, 0.0f), outColor);
// }
//}
// ---- Draw Tonemap curve ----
if (_DrawTonemapCurve)
{
val = GetTonemappedValueAtLocation(unormCoord.x / _ScreenSize.x, currExposure);
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(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz;
float pipFraction = 0.33f;
uint borderSize = 3;
float2 topRight = pipFraction * _ScreenSize.xy;
if (all(input.positionCS.xy < topRight))
{
float2 scaledUV = uv / pipFraction;
float3 pipColor = _ExposureDebugParams.x > 0 ? float3(1.0f, 1.0f, 1.0f) : SAMPLE_TEXTURE2D_X_LOD(_SourceTexture, s_linear_clamp_sampler, scaledUV, 0.0).xyz;
float luminance = SampleLuminance(scaledUV);
float weight = WeightSample(scaledUV.xy * _ScreenSize.xy / _RTHandleScale.xy, _ScreenSize.xy, luminance);
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
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
float3 textColor = 0.0f;
float2 sidebarSize = float2(0.9, 0.02) * _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);
int2 unormCoord = input.positionCS.xy;
uint2 textLocation = uint2(_MousePixelCoord.xy);
float evInRange = (ev - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin);
if (ev < ParamExposureLimitMax && ev > ParamExposureLimitMin)
{
outputColor = ToHeat(evInRange);
}
else if (ev > ParamExposureLimitMax)
{
outputColor = 1.0f;
}
else if (ev < ParamExposureLimitMin)
{
outputColor = 0.0f;
}
// Get value at indicator
float2 indicatorUV = _MousePixelCoord.xy * _ScreenSize.zw * _RTHandleScale.xy;
float indicatorEV = GetEVAtLocation(indicatorUV);
float indicatorEVRange = (indicatorEV - ParamExposureLimitMin) / (ParamExposureLimitMax - ParamExposureLimitMin);
float extremeMargin = 5 * _ScreenSize.z * _RTHandleScale.x;
DrawHeatSideBar(uv, sidebarBottomLeft, endPointSidebar, indicatorEVRange, 0.66f, sidebarSize, extremeMargin, outputColor);
// Label bar
float2 borderSize = 2 * _ScreenSize.zw * _RTHandleScale.xy;
if (uv.y < heightLabelBar &&
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 / _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;
[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);
}
int displayTextOffsetX = DEBUG_FONT_TEXT_WIDTH;
textLocation = uint2(_MousePixelCoord.x + displayTextOffsetX + 1, _MousePixelCoord.y - 1);
DrawFloatExplicitPrecision(indicatorEV, 1.0f - textColor, unormCoord, 1, textLocation, outputColor.rgb);
textLocation = uint2(_MousePixelCoord.x + displayTextOffsetX, _MousePixelCoord.y);
DrawFloatExplicitPrecision(indicatorEV, textColor, unormCoord, 1, textLocation, outputColor.rgb);
textLocation = uint2(_MousePixelCoord.x + 1, _MousePixelCoord.y - 1);
DrawCharacter('X', 1.0f - textColor, unormCoord, textLocation, outputColor.rgb);
textLocation = _MousePixelCoord.xy;
DrawCharacter('X', textColor, unormCoord, 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(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz;
float3 outputColor = color;
// 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 = 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, float3(0.125,0.125,0.125), 0.4f, maxValue, minPercentileLoc, maxPercentileLoc, outputColor);
float currExposure = _ExposureTexture[int2(0, 0)].y;
float targetExposure = _ExposureDebugTexture[int2(0, 0)].x;
uint2 unormCoord = input.positionCS.xy;
float3 textColor = float3(0.5f, 0.5f, 0.5f);
uint2 textLocation = uint2(DEBUG_FONT_TEXT_WIDTH * 0.5, DEBUG_FONT_TEXT_WIDTH * 0.5 + histFrameHeight * (_ScreenSize.y / _RTHandleScale.y));
DrawCharacter('C', textColor, unormCoord, textLocation, outputColor.rgb, 1, 10);
DrawCharacter('u', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('r', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('r', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('e', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('n', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('t', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter(' ', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('E', textColor, unormCoord, textLocation, outputColor.rgb, 1, 10);
DrawCharacter('x', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('p', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('o', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('s', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('u', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('r', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('e', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter(':', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
textLocation.x += DEBUG_FONT_TEXT_WIDTH * 0.5f;
DrawFloatExplicitPrecision(currExposure, textColor, unormCoord, 3, textLocation, outputColor.rgb);
textLocation = uint2(DEBUG_FONT_TEXT_WIDTH * 0.5, textLocation.y + DEBUG_FONT_TEXT_WIDTH);
DrawCharacter('T', textColor, unormCoord, textLocation, outputColor.rgb, 1, 10);
DrawCharacter('a', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('r', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('g', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('e', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('t', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter(' ', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('E', textColor, unormCoord, textLocation, outputColor.rgb, 1, 10);
DrawCharacter('x', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('p', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('o', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('s', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('u', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('r', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('e', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter(':', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
textLocation.x += DEBUG_FONT_TEXT_WIDTH * 0.5f;
DrawFloatExplicitPrecision(targetExposure, textColor, unormCoord, 3, textLocation, outputColor.rgb);
textLocation = int2(DEBUG_FONT_TEXT_WIDTH * 0.5f, textLocation.y + DEBUG_FONT_TEXT_WIDTH);
DrawCharacter('E', textColor, unormCoord, textLocation, outputColor.rgb, 1, 10);
DrawCharacter('x', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('p', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('o', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('s', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('u', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('r', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('e', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter(' ', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('C', textColor, unormCoord, textLocation, outputColor.rgb, 1, 10);
DrawCharacter('o', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('m', textColor, unormCoord, textLocation, outputColor.rgb, 1, 8);
DrawCharacter('p', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('e', textColor, unormCoord, textLocation, outputColor.rgb, 1, 8);
DrawCharacter('n', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('s', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('a', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('t', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('i', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('o', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter('n', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
DrawCharacter(':', textColor, unormCoord, textLocation, outputColor.rgb, 1, 7);
textLocation.x += DEBUG_FONT_TEXT_WIDTH * 0.5f;
DrawFloatExplicitPrecision(ParamExposureCompensation, textColor, unormCoord, 3, textLocation, outputColor.rgb);
return outputColor;
}
StructuredBuffer<uint4> _FullImageHistogram;
float3 FragImageHistogram(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
float3 color = SAMPLE_TEXTURE2D_X_LOD(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz;
float3 outputColor = color;
float heightLabelBar = (DEBUG_FONT_TEXT_WIDTH * 1.25) * _ScreenSize.w * _RTHandleScale.y;
uint maxValue = 0;
uint maxLuma = 0;
for (int i = 0; i < 256; ++i)
{
uint histogramVal = Max3(_FullImageHistogram[i].x, _FullImageHistogram[i].y, _FullImageHistogram[i].z);
maxValue = max(histogramVal, maxValue);
maxLuma = max(_FullImageHistogram[i].w, maxLuma);
}
float histFrameHeight = 0.2 * _RTHandleScale.y;
float safeBand = 1.0f / 255.0f;
float binLocMin = safeBand;
float binLocMax = 1.0f - safeBand;
if (DrawEmptyFrame(uv, float3(0.125, 0.125, 0.125), 0.4, histFrameHeight, heightLabelBar, outputColor))
{
// Draw labels
const int labelCount = 12;
int minLabelLocationX = DEBUG_FONT_TEXT_WIDTH * 0.25;
int maxLabelLocationX = _ScreenSize.x - (DEBUG_FONT_TEXT_WIDTH * 3);
int labelLocationY = 0.0f;
uint2 unormCoord = input.positionCS.xy;
for (int i = 0; i <= labelCount; ++i)
{
float t = rcp(labelCount) * i;
uint2 labelLoc = uint2((uint)lerp(minLabelLocationX, maxLabelLocationX, t), labelLocationY);
float labelValue = lerp(0.0, 255.0, t);
labelLoc.x += 2;
DrawInteger(labelValue, float3(1.0f, 1.0f, 1.0f), unormCoord, labelLoc, outputColor.rgb);
}
float remappedX = (((float)unormCoord.x / _ScreenSize.x) - binLocMin) / (binLocMax - binLocMin);
// Draw bins
uint bin = saturate(remappedX) * 255;
float4 val = _FullImageHistogram[bin];
val /= float4(maxValue, maxValue, maxValue, maxLuma);
val *= 0.95*(histFrameHeight - heightLabelBar);
val += heightLabelBar;
if (_FinalImageHistogramRGB > 0)
{
float3 alphas = 0;
if (uv.y < val.x && uv.y > heightLabelBar)
alphas.x = 0.3333f;
if (uv.y < val.y && uv.y > heightLabelBar)
alphas.y = 0.3333f;
if (uv.y < val.z && uv.y > heightLabelBar)
alphas.z = 0.3333f;
outputColor = outputColor * (1.0f - (alphas.x + alphas.y + alphas.z)) + alphas;
}
else
{
if (uv.y < val.w && uv.y > heightLabelBar)
outputColor = 0.3333f;
}
}
return outputColor;
}
ENDHLSL
SubShader
{
Tags{ "RenderPipeline" = "HDRenderPipeline" }
Pass
{
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment FragSceneEV100
ENDHLSL
}
Pass
{
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment FragMetering
ENDHLSL
}
Pass
{
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment FragHistogram
ENDHLSL
}
Pass
{
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment FragImageHistogram
ENDHLSL
}
}
Fallback Off
}