diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md
index cd7a777a286..b1a2fc0499e 100644
--- a/com.unity.render-pipelines.high-definition/CHANGELOG.md
+++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md
@@ -152,6 +152,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added compute shader stripping.
- Added Cull Mode option for opaque materials and ShaderGraphs.
- Added scene view exposure override.
+- Added support for exposure curve remapping for min/max limits.
### Fixed
- Fix when rescale probe all direction below zero (1219246)
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 14fc781f072..63f9e976fc5 100644
--- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/ExposureEditor.cs
@@ -16,7 +16,9 @@ sealed class ExposureEditor : VolumeComponentEditor
SerializedDataParameter m_LimitMin;
SerializedDataParameter m_LimitMax;
SerializedDataParameter m_CurveMap;
-
+ SerializedDataParameter m_CurveMin;
+ SerializedDataParameter m_CurveMax;
+
SerializedDataParameter m_AdaptationMode;
SerializedDataParameter m_AdaptationSpeedDarkToLight;
SerializedDataParameter m_AdaptationSpeedLightToDark;
@@ -52,7 +54,9 @@ public override void OnEnable()
m_LimitMin = Unpack(o.Find(x => x.limitMin));
m_LimitMax = Unpack(o.Find(x => x.limitMax));
m_CurveMap = Unpack(o.Find(x => x.curveMap));
-
+ m_CurveMin = Unpack(o.Find(x => x.limitMinCurveMap));
+ m_CurveMax = Unpack(o.Find(x => x.limitMaxCurveMap));
+
m_AdaptationMode = Unpack(o.Find(x => x.adaptationMode));
m_AdaptationSpeedDarkToLight = Unpack(o.Find(x => x.adaptationSpeedDarkToLight));
m_AdaptationSpeedLightToDark = Unpack(o.Find(x => x.adaptationSpeedLightToDark));
@@ -137,11 +141,18 @@ public override void OnInspectorGUI()
// EditorGUILayout.HelpBox("Luminance source buffer isn't supported yet.", MessageType.Warning);
if (mode == (int)ExposureMode.CurveMapping)
+ {
PropertyField(m_CurveMap);
-
+ PropertyField(m_CurveMin, EditorGUIUtility.TrTextContent("Limit Min"));
+ PropertyField(m_CurveMax, EditorGUIUtility.TrTextContent("Limit Max"));
+ }
+ else if (!(mode == (int)ExposureMode.AutomaticHistogram && m_HistogramCurveRemapping.value.boolValue))
+ {
+ PropertyField(m_LimitMin);
+ PropertyField(m_LimitMax);
+ }
+
PropertyField(m_Compensation);
- PropertyField(m_LimitMin);
- PropertyField(m_LimitMax);
if(mode == (int)ExposureMode.AutomaticHistogram)
{
@@ -152,6 +163,8 @@ public override void OnInspectorGUI()
if (m_HistogramCurveRemapping.value.boolValue)
{
PropertyField(m_CurveMap);
+ PropertyField(m_CurveMin, EditorGUIUtility.TrTextContent("Limit Min"));
+ PropertyField(m_CurveMax, EditorGUIUtility.TrTextContent("Limit Max"));
}
}
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 fdef62f313f..45b560bad65 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
@@ -64,6 +64,20 @@ public sealed class Exposure : VolumeComponent, IPostProcessComponent
[Tooltip("Specifies a curve that remaps the Scene exposure on the x-axis to the exposure you want on the y-axis.")]
public AnimationCurveParameter curveMap = new AnimationCurveParameter(AnimationCurve.Linear(-10f, -10f, 20f, 20f)); // TODO: Use TextureCurve instead?
+ ///
+ /// Specifies a curve that determines for each current exposure value (x-value) what minimum value is allowed to auto-adaptation (y-axis).
+ /// This parameter is only used when is set.
+ ///
+ [Tooltip("Specifies a curve that determines for each current exposure value (x-value) what minimum value is allowed to auto-adaptation (y-axis).")]
+ public AnimationCurveParameter limitMinCurveMap = new AnimationCurveParameter(AnimationCurve.Linear(-10f, -12f, 20f, 18f));
+
+ ///
+ /// Specifies a curve that determines for each current exposure value (x-value) what maximum value is allowed to auto-adaptation (y-axis).
+ /// This parameter is only used when is set.
+ ///
+ [Tooltip("Specifies a curve that determines for each current exposure value (x-value) what maximum value is allowed to auto-adaptation (y-axis).")]
+ public AnimationCurveParameter limitMaxCurveMap = new AnimationCurveParameter(AnimationCurve.Linear(-10f, -8f, 20f, 22f));
+
///
/// Specifies the method that HDRP uses to change the exposure when the Camera moves from dark to light and vice versa.
/// This parameter is only used when or is set.
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 9f0b17d71bf..487069c6a43 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs
@@ -1017,11 +1017,15 @@ RTHandle Allocator(string id, int frameIndex, RTHandleSystem rtHandleSystem)
previous = camera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.Exposure);
}
- void PrepareExposureCurveData(AnimationCurve curve, out float min, out float max)
+ void PrepareExposureCurveData(out float min, out float max)
{
+ var curve = m_Exposure.curveMap.value;
+ var minCurve = m_Exposure.limitMinCurveMap.value;
+ var maxCurve = m_Exposure.limitMaxCurveMap.value;
+
if (m_ExposureCurveTexture == null)
{
- m_ExposureCurveTexture = new Texture2D(k_ExposureCurvePrecision, 1, TextureFormat.RHalf, false, true)
+ m_ExposureCurveTexture = new Texture2D(k_ExposureCurvePrecision, 1, TextureFormat.RGBAHalf, false, true)
{
name = "Exposure Curve",
filterMode = FilterMode.Bilinear,
@@ -1029,6 +1033,11 @@ void PrepareExposureCurveData(AnimationCurve curve, out float min, out float max
};
}
+ bool minCurveHasPoints = minCurve.length > 0;
+ bool maxCurveHasPoints = maxCurve.length > 0;
+ float defaultMin = -100.0f;
+ float defaultMax = 100.0f;
+
var pixels = m_ExposureCurveColorArray;
// Fail safe in case the curve is deleted / has 0 point
@@ -1047,7 +1056,13 @@ void PrepareExposureCurveData(AnimationCurve curve, out float min, out float max
float step = (max - min) / (k_ExposureCurvePrecision - 1f);
for (int i = 0; i < k_ExposureCurvePrecision; i++)
- pixels[i] = new Color(curve.Evaluate(min + step * i), 0f, 0f, 0f);
+ {
+ float currTime = min + step * i;
+ pixels[i] = new Color(curve.Evaluate(currTime),
+ minCurveHasPoints ? minCurve.Evaluate(currTime) : defaultMin,
+ maxCurveHasPoints ? maxCurve.Evaluate(currTime) : defaultMax,
+ 0f);
+ }
}
m_ExposureCurveTexture.SetPixels(pixels);
@@ -1124,7 +1139,7 @@ void DoDynamicExposure(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer)
}
else if (m_Exposure.mode.value == ExposureMode.CurveMapping)
{
- PrepareExposureCurveData(m_Exposure.curveMap.value, out float min, out float max);
+ PrepareExposureCurveData(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, ColorUtils.lensImperfectionExposureScale, ColorUtils.s_LightMeterCalibrationConstant));
@@ -1199,7 +1214,7 @@ void DoHistogramBasedExposure(CommandBuffer cmd, HDCamera camera, RTHandle sourc
m_ExposureVariants[3] = 0;
if (m_Exposure.histogramUseCurveRemapping.value)
{
- PrepareExposureCurveData(m_Exposure.curveMap.value, out float min, out float max);
+ PrepareExposureCurveData(out float min, out float max);
cmd.SetComputeVectorParam(cs, HDShaderIDs._ExposureParams2, new Vector4(min, max, ColorUtils.lensImperfectionExposureScale, ColorUtils.s_LightMeterCalibrationConstant));
m_ExposureVariants[3] = 2;
}
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 88e7a7490ce..3d313dab02c 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
@@ -127,8 +127,11 @@ void KReduction(uint2 groupId : SV_GroupID, uint2 groupThreadId : SV_GroupThread
case 2u:
{
// Curve remapping
- float exposure = CurveRemap(avgLuminance);
+ float minExposure = ParamExposureLimitMin;
+ float maxExposure = ParamExposureLimitMax;
+ float exposure = CurveRemap(avgLuminance, minExposure, maxExposure);
exposure = AdaptExposure(exposure - ParamExposureCompensation);
+ exposure = clamp(exposure, minExposure, maxExposure);
_OutputTexture[groupId.xy] = float2(ConvertEV100ToExposure(exposure, LensImperfectionExposureScale), 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 0b16e8d8641..7f74f3af74a 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
@@ -122,10 +122,13 @@ float AdaptExposure(float exposure)
}
}
-float CurveRemap(float inEV)
+float CurveRemap(float inEV, out float limitMin, out float limitMax)
{
float remap = saturate((inEV - ParamCurveMin) / (ParamCurveMax - ParamCurveMin));
- return SAMPLE_TEXTURE2D_LOD(_ExposureCurveTexture, s_linear_clamp_sampler, float2(remap, 0.0), 0.0).x;
+ float3 curveSample = SAMPLE_TEXTURE2D_LOD(_ExposureCurveTexture, s_linear_clamp_sampler, float2(remap, 0.0), 0.0).xyz;
+ limitMin = curveSample.y;
+ limitMax = curveSample.z;
+ return curveSample.x;
}
#endif
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 8f12e2925ef..a72bc28bac3 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
@@ -165,13 +165,15 @@ void KHistogramReduce(uint3 dispatchThreadId : SV_DispatchThreadID)
w = max(w, 1e-4f);
float avgEV = evProcessedSum * rcp(w);
+ float minExposure = ParamExposureLimitMin;
+ float maxExposure = ParamExposureLimitMax;
if (ParamEvaluateMode == 2)
{
- avgEV = CurveRemap(avgEV);
+ avgEV = CurveRemap(avgEV, minExposure, maxExposure);
}
float exposure = AdaptExposure(avgEV - ParamExposureCompensation);
- exposure = clamp(exposure, ParamExposureLimitMin, ParamExposureLimitMax);
+ exposure = clamp(exposure, minExposure, maxExposure);
_OutputTexture[uint2(0, 0)] = float2(ConvertEV100ToExposure(exposure, LensImperfectionExposureScale), exposure);
#ifdef OUTPUT_DEBUG_DATA
_ExposureDebugTexture[uint2(0, 0)] = float2(avgEV - ParamExposureCompensation, 0.0f);