From ee44b89ad19cd76b9ce1d938238d567a73fa5081 Mon Sep 17 00:00:00 2001 From: Chman Date: Mon, 27 Feb 2017 11:49:18 +0100 Subject: [PATCH] Improved eye adaptation to make it more intuitive and easy to use --- .../Editor/Models/EyeAdaptationModelEditor.cs | 38 +++++++++++++------ .../Resources/Shaders/EyeAdaptation.shader | 7 +++- .../Components/EyeAdaptationComponent.cs | 8 +++- .../Runtime/Models/EyeAdaptationModel.cs | 22 ++++++----- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/PostProcessing/Editor/Models/EyeAdaptationModelEditor.cs b/PostProcessing/Editor/Models/EyeAdaptationModelEditor.cs index abb07bd4..94c49f2c 100644 --- a/PostProcessing/Editor/Models/EyeAdaptationModelEditor.cs +++ b/PostProcessing/Editor/Models/EyeAdaptationModelEditor.cs @@ -12,7 +12,8 @@ public class EyeAdaptationModelEditor : PostProcessingModelEditor SerializedProperty m_HighPercent; SerializedProperty m_MinLuminance; SerializedProperty m_MaxLuminance; - SerializedProperty m_ExposureCompensation; + SerializedProperty m_KeyValue; + SerializedProperty m_DynamicKeyValue; SerializedProperty m_AdaptationType; SerializedProperty m_SpeedUp; SerializedProperty m_SpeedDown; @@ -25,7 +26,8 @@ public override void OnEnable() m_HighPercent = FindSetting((Settings x) => x.highPercent); m_MinLuminance = FindSetting((Settings x) => x.minLuminance); m_MaxLuminance = FindSetting((Settings x) => x.maxLuminance); - m_ExposureCompensation = FindSetting((Settings x) => x.exposureCompensation); + m_KeyValue = FindSetting((Settings x) => x.keyValue); + m_DynamicKeyValue = FindSetting((Settings x) => x.dynamicKeyValue); m_AdaptationType = FindSetting((Settings x) => x.adaptationType); m_SpeedUp = FindSetting((Settings x) => x.speedUp); m_SpeedDown = FindSetting((Settings x) => x.speedDown); @@ -36,27 +38,39 @@ public override void OnEnable() public override void OnInspectorGUI() { if (!GraphicsUtils.supportsDX11) - { EditorGUILayout.HelpBox("This effect requires support for compute shaders. Enabling it won't do anything on unsupported platforms.", MessageType.Warning); - } - EditorGUILayout.PropertyField(m_LogMin, EditorGUIHelper.GetContent("Histogram Log Min")); - EditorGUILayout.PropertyField(m_LogMax, EditorGUIHelper.GetContent("Histogram Log Max")); + EditorGUILayout.LabelField("Luminosity range", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_LogMin, EditorGUIHelper.GetContent("Minimum (EV)")); + EditorGUILayout.PropertyField(m_LogMax, EditorGUIHelper.GetContent("Maximum (EV)")); + EditorGUI.indentLevel--; EditorGUILayout.Space(); + EditorGUILayout.LabelField("Auto exposure", EditorStyles.boldLabel); + EditorGUI.indentLevel++; float low = m_LowPercent.floatValue; float high = m_HighPercent.floatValue; - EditorGUILayout.MinMaxSlider(EditorGUIHelper.GetContent("Filter|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."), ref low, ref high, 1f, 99f); + EditorGUILayout.MinMaxSlider(EditorGUIHelper.GetContent("Histogram filtering|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."), ref low, ref high, 1f, 99f); m_LowPercent.floatValue = low; m_HighPercent.floatValue = high; - EditorGUILayout.PropertyField(m_MinLuminance); - EditorGUILayout.PropertyField(m_MaxLuminance); - EditorGUILayout.PropertyField(m_ExposureCompensation); + EditorGUILayout.PropertyField(m_MinLuminance, EditorGUIHelper.GetContent("Minimum (EV)")); + EditorGUILayout.PropertyField(m_MaxLuminance, EditorGUIHelper.GetContent("Maximum (EV)")); + EditorGUILayout.PropertyField(m_DynamicKeyValue); - EditorGUILayout.PropertyField(m_AdaptationType); + if (!m_DynamicKeyValue.boolValue) + EditorGUILayout.PropertyField(m_KeyValue); + + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Adaptation", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + + EditorGUILayout.PropertyField(m_AdaptationType, EditorGUIHelper.GetContent("Type")); if (m_AdaptationType.intValue == (int)EyeAdaptationModel.EyeAdaptationType.Progressive) { @@ -65,6 +79,8 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_SpeedDown); EditorGUI.indentLevel--; } + + EditorGUI.indentLevel--; } } } diff --git a/PostProcessing/Resources/Shaders/EyeAdaptation.shader b/PostProcessing/Resources/Shaders/EyeAdaptation.shader index 08504d23..8ec509d6 100644 --- a/PostProcessing/Resources/Shaders/EyeAdaptation.shader +++ b/PostProcessing/Resources/Shaders/EyeAdaptation.shader @@ -8,6 +8,7 @@ Shader "Hidden/Post FX/Eye Adaptation" CGINCLUDE #pragma target 4.5 + #pragma multi_compile __ AUTO_KEY_VALUE #include "UnityCG.cginc" #include "Common.cginc" #include "EyeAdaptation.cginc" @@ -86,8 +87,12 @@ Shader "Hidden/Post FX/Eye Adaptation" { avgLuminance = max(EPSILON, avgLuminance); - //half keyValue = 1.03 - (2.0 / (2.0 + log2(avgLuminance + 1.0))); + #if AUTO_KEY_VALUE + half keyValue = 1.03 - (2.0 / (2.0 + log2(avgLuminance + 1.0))); + #else half keyValue = _ExposureCompensation; + #endif + half exposure = keyValue / avgLuminance; return exposure; diff --git a/PostProcessing/Runtime/Components/EyeAdaptationComponent.cs b/PostProcessing/Runtime/Components/EyeAdaptationComponent.cs index c50eefe3..5b6a4d1f 100644 --- a/PostProcessing/Runtime/Components/EyeAdaptationComponent.cs +++ b/PostProcessing/Runtime/Components/EyeAdaptationComponent.cs @@ -84,6 +84,7 @@ public Texture Prepare(RenderTexture source, Material uberMaterial) m_EyeCompute = Resources.Load("Shaders/EyeHistogram"); var material = context.materialFactory.Get("Hidden/Post FX/Eye Adaptation"); + material.shaderKeywords = null; if (m_HistogramBuffer == null) m_HistogramBuffer = new ComputeBuffer(k_HistogramBins, sizeof(uint)); @@ -124,10 +125,13 @@ public Texture Prepare(RenderTexture source, Material uberMaterial) // Compute auto exposure material.SetBuffer("_Histogram", m_HistogramBuffer); // No (int, buffer) overload for SetBuffer ? - material.SetVector(Uniforms._Params, new Vector4(settings.lowPercent * 0.01f, settings.highPercent * 0.01f, settings.minLuminance, settings.maxLuminance)); + material.SetVector(Uniforms._Params, new Vector4(settings.lowPercent * 0.01f, settings.highPercent * 0.01f, Mathf.Exp(settings.minLuminance * 0.69314718055994530941723212145818f), Mathf.Exp(settings.maxLuminance * 0.69314718055994530941723212145818f))); material.SetVector(Uniforms._Speed, new Vector2(settings.speedDown, settings.speedUp)); material.SetVector(Uniforms._ScaleOffsetRes, scaleOffsetRes); - material.SetFloat(Uniforms._ExposureCompensation, settings.exposureCompensation); + material.SetFloat(Uniforms._ExposureCompensation, settings.keyValue); + + if (settings.dynamicKeyValue) + material.EnableKeyword("AUTO_KEY_VALUE"); if (m_FirstFrame || !Application.isPlaying) { diff --git a/PostProcessing/Runtime/Models/EyeAdaptationModel.cs b/PostProcessing/Runtime/Models/EyeAdaptationModel.cs index 440a34be..bf41a036 100644 --- a/PostProcessing/Runtime/Models/EyeAdaptationModel.cs +++ b/PostProcessing/Runtime/Models/EyeAdaptationModel.cs @@ -20,14 +20,17 @@ public struct Settings [Range(1f, 99f), Tooltip("Filters the bright part of the histogram when computing the average luminance to avoid very dark pixels from contributing to the auto exposure. Unit is in percent.")] public float highPercent; - [Min(0f), Tooltip("Minimum average luminance to consider for auto exposure.")] + [Tooltip("Minimum average luminance to consider for auto exposure (in EV).")] public float minLuminance; - [Min(0f), Tooltip("Maximum average luminance to consider for auto exposure.")] + [Tooltip("Maximum average luminance to consider for auto exposure (in EV).")] public float maxLuminance; [Min(0f), Tooltip("Exposure bias. Use this to control the global exposure of the scene.")] - public float exposureCompensation; + public float keyValue; + + [Tooltip("Set this to true to let Unity handle the key value automatically based on average luminance.")] + public bool dynamicKeyValue; [Tooltip("Use \"Progressive\" if you want the auto exposure to be animated. Use \"Fixed\" otherwise.")] public EyeAdaptationType adaptationType; @@ -38,10 +41,10 @@ public struct Settings [Min(0f), Tooltip("Adaptation speed from a light to a dark environment.")] public float speedDown; - [Range(-16, -1), Tooltip("Lower bound for the brightness range of the generated histogram (Log2).")] + [Range(-16, -1), Tooltip("Lower bound for the brightness range of the generated histogram (in EV). The bigger the spread between min & max, the lower the precision will be.")] public int logMin; - [Range(1, 16), Tooltip("Upper bound for the brightness range of the generated histogram (Log2).")] + [Range(1, 16), Tooltip("Upper bound for the brightness range of the generated histogram (in EV). The bigger the spread between min & max, the lower the precision will be.")] public int logMax; public static Settings defaultSettings @@ -50,12 +53,13 @@ public static Settings defaultSettings { return new Settings { - lowPercent = 65f, + lowPercent = 45f, highPercent = 95f, - minLuminance = 0.03f, - maxLuminance = 2f, - exposureCompensation = 0.5f, + minLuminance = -5f, + maxLuminance = 1f, + keyValue = 0.25f, + dynamicKeyValue = true, adaptationType = EyeAdaptationType.Progressive, speedUp = 2f,