diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
index 7209768671c..495de3313a3 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
@@ -671,7 +671,7 @@ static void DrawEmissionContentFiltered(SerializedHDLight serialized, Editor own
var temperatureSliderRect = lineRect;
temperatureSliderRect.x += EditorGUIUtility.labelWidth + k_ValueUnitSeparator;
temperatureSliderRect.width -= EditorGUIUtility.labelWidth + k_ValueUnitSeparator;
- k_LightUnitSliderUIDrawer.DrawTemperatureSlider(serialized.settings, serialized.settings.colorTemperature, temperatureSliderRect);
+ TemperatureSliderUIDrawer.Draw(serialized.settings, serialized.serializedObject, serialized.settings.colorTemperature, temperatureSliderRect);
// Value and unit label
// Match const defined in EditorGUI.cs
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPiecewiseLightUnitSlider.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPiecewiseLightUnitSlider.cs
new file mode 100644
index 00000000000..fd64df7927c
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPiecewiseLightUnitSlider.cs
@@ -0,0 +1,131 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Rendering.HighDefinition;
+using UnityEngine.Experimental.Rendering;
+
+namespace UnityEditor.Rendering.HighDefinition
+{
+ ///
+ /// Formats the provided descriptor into a piece-wise linear slider with contextual slider markers, tooltips, and icons.
+ ///
+ class HDPiecewiseLightUnitSlider : LightUnitSlider
+ {
+ struct Piece
+ {
+ public Vector2 domain;
+ public Vector2 range;
+
+ public float directM;
+ public float directB;
+ public float inverseM;
+ public float inverseB;
+ }
+
+ // Piecewise function indexed by value ranges.
+ private readonly Dictionary m_PiecewiseFunctionMap = new Dictionary();
+
+ static void ComputeTransformationParameters(float x0, float x1, float y0, float y1, out float m, out float b)
+ {
+ m = (y0 - y1) / (x0 - x1);
+ b = (m * -x0) + y0;
+ }
+
+ static float DoTransformation(in float x, in float m, in float b) => (m * x) + b;
+
+ // Ensure clamping to (0,1) as sometimes the function evaluates to slightly below 0 (breaking the handle).
+ static float ValueToSlider(Piece p, float x) => Mathf.Clamp01(DoTransformation(x, p.inverseM, p.inverseB));
+ static float SliderToValue(Piece p, float x) => DoTransformation(x, p.directM, p.directB);
+
+ // Ideally we want a continuous, monotonically increasing function, but this is useful as we can easily fit a
+ // distribution to a set of (huge) value ranges onto a slider.
+ public HDPiecewiseLightUnitSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor)
+ {
+ // Sort the ranges into ascending order
+ var sortedRanges = m_Descriptor.valueRanges.OrderBy(x => x.value.x).ToArray();
+ var sliderDistribution = m_Descriptor.sliderDistribution;
+
+ // Compute the transformation for each value range.
+ for (int i = 0; i < sortedRanges.Length; i++)
+ {
+ var r = sortedRanges[i].value;
+
+ var x0 = sliderDistribution[i + 0];
+ var x1 = sliderDistribution[i + 1];
+ var y0 = r.x;
+ var y1 = r.y;
+
+ Piece piece;
+ piece.domain = new Vector2(x0, x1);
+ piece.range = new Vector2(y0, y1);
+
+ ComputeTransformationParameters(x0, x1, y0, y1, out piece.directM, out piece.directB);
+
+ // Compute the inverse
+ ComputeTransformationParameters(y0, y1, x0, x1, out piece.inverseM, out piece.inverseB);
+
+ m_PiecewiseFunctionMap.Add(sortedRanges[i].value, piece);
+ }
+ }
+
+ protected override float GetPositionOnSlider(float value, Vector2 valueRange)
+ {
+ if (!m_PiecewiseFunctionMap.TryGetValue(valueRange, out var piecewise))
+ return -1f;
+
+ return ValueToSlider(piecewise, value);
+ }
+
+ // Search for the corresponding piece-wise function to a value on the domain and update the input piece to it.
+ // Returns true if search was successful and an update was made, false otherwise.
+ bool UpdatePiece(ref Piece piece, float x)
+ {
+ foreach (var pair in m_PiecewiseFunctionMap)
+ {
+ var p = pair.Value;
+
+ if (x >= p.domain.x && x <= p.domain.y)
+ {
+ piece = p;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void SliderOutOfBounds(Rect rect, ref float value)
+ {
+ EditorGUI.BeginChangeCheck();
+ var internalValue = GUI.HorizontalSlider(rect, value, 0f, 1f);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Piece p = new Piece();
+ UpdatePiece(ref p, internalValue);
+ value = SliderToValue(p, internalValue);
+ }
+ }
+
+ protected override void DoSlider(Rect rect, ref float value, Vector2 sliderRange, Vector2 valueRange)
+ {
+ // Map the internal slider value to the current piecewise function
+ if (!m_PiecewiseFunctionMap.TryGetValue(valueRange, out var piece))
+ {
+ // Assume that if the piece is not found, that means the unit value is out of bounds.
+ SliderOutOfBounds(rect, ref value);
+ return;
+ }
+
+ // Maintain an internal value to support a single linear continuous function
+ EditorGUI.BeginChangeCheck();
+ var internalValue = GUI.HorizontalSlider(rect, ValueToSlider(piece, value), 0f, 1f);
+ if (EditorGUI.EndChangeCheck())
+ {
+ // Ensure that the current function piece is being used to transform the value
+ UpdatePiece(ref piece, internalValue);
+ value = SliderToValue(piece, internalValue);
+ }
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPiecewiseLightUnitSlider.cs.meta b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPiecewiseLightUnitSlider.cs.meta
new file mode 100644
index 00000000000..8dbac8e9cd8
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPiecewiseLightUnitSlider.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f01918813898d7b4382f640c4a0e1046
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPunctualLightUnitSlider.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPunctualLightUnitSlider.cs
new file mode 100644
index 00000000000..a2a9af4f072
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPunctualLightUnitSlider.cs
@@ -0,0 +1,99 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Rendering.HighDefinition;
+using UnityEngine.Experimental.Rendering;
+
+namespace UnityEditor.Rendering.HighDefinition
+{
+ ///
+ /// Formats the provided descriptor into a punctual light unit slider with contextual slider markers, tooltips, and icons.
+ ///
+ class HDPunctualLightUnitSlider : HDPiecewiseLightUnitSlider
+ {
+ public HDPunctualLightUnitSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor) { }
+
+ private SerializedHDLight m_Light;
+ private Editor m_Editor;
+ private LightUnit m_Unit;
+ private bool m_SpotReflectorEnabled;
+
+ // Note: these should be in sync with LightUnit
+ private static string[] k_UnitNames =
+ {
+ "Lumen",
+ "Candela",
+ "Lux",
+ "Nits",
+ "EV",
+ };
+
+ public void Setup(LightUnit unit, SerializedHDLight light, Editor owner)
+ {
+ m_Unit = unit;
+ m_Light = light;
+ m_Editor = owner;
+
+ // Cache the spot reflector state as we will need to revert back to it after treating the slider as point light.
+ m_SpotReflectorEnabled = light.enableSpotReflector.boolValue;
+ }
+
+ public override void Draw(Rect rect, SerializedProperty value, ref float floatValue)
+ {
+ // Convert the incoming unit value into Lumen as the punctual slider is always in these terms (internally)
+ float convertedValue = UnitToLumen(floatValue);
+
+ EditorGUI.BeginChangeCheck();
+ base.Draw(rect, value, ref convertedValue);
+ if (EditorGUI.EndChangeCheck())
+ floatValue = LumenToUnit(convertedValue);
+ }
+
+ protected override GUIContent GetLightUnitTooltip(string baseTooltip, float value, string unit)
+ {
+ // Convert the internal lumens into the actual light unit value
+ value = LumenToUnit(value);
+ unit = k_UnitNames[(int)m_Unit];
+
+ return base.GetLightUnitTooltip(baseTooltip, value, unit);
+ }
+
+ float UnitToLumen(float value)
+ {
+ if (m_Unit == LightUnit.Lumen)
+ return value;
+
+ // Punctual slider currently does not have any regard for spot shape/reflector.
+ // Conversions need to happen as if light is a point, and this is the only setting that influences that.
+ m_Light.enableSpotReflector.boolValue = false;
+
+ return HDLightUI.ConvertLightIntensity(m_Unit, LightUnit.Lumen, m_Light, m_Editor, value);
+ }
+
+ float LumenToUnit(float value)
+ {
+ if (m_Unit == LightUnit.Lumen)
+ return value;
+
+ // Once again temporarily disable reflector in case we called this for tooltip or context menu preset.
+ m_Light.enableSpotReflector.boolValue = false;
+
+ value = HDLightUI.ConvertLightIntensity(LightUnit.Lumen, m_Unit, m_Light, m_Editor, value);
+
+ // Restore the state of spot reflector on the light.
+ m_Light.enableSpotReflector.boolValue = m_SpotReflectorEnabled;
+
+ return value;
+ }
+
+ protected override void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
+ {
+ m_Light?.Update();
+
+ // Convert to the actual unit value.
+ value.floatValue = LumenToUnit(preset.presetValue);
+
+ m_Light?.Apply();
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPunctualLightUnitSlider.cs.meta b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPunctualLightUnitSlider.cs.meta
new file mode 100644
index 00000000000..7706e6b2609
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/HDPunctualLightUnitSlider.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 76975b3cce013684cb3d854af3d22d46
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/LightUnitSlider.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/LightUnitSlider.cs
index 76da41d46c8..84fe914d9f8 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/LightUnitSlider.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/LightUnitSlider.cs
@@ -254,351 +254,22 @@ protected virtual float GetPositionOnSlider(float value)
}
}
- ///
- /// Formats the provided descriptor into a piece-wise linear slider with contextual slider markers, tooltips, and icons.
- ///
- class PiecewiseLightUnitSlider : LightUnitSlider
- {
- struct Piece
- {
- public Vector2 domain;
- public Vector2 range;
-
- public float directM;
- public float directB;
- public float inverseM;
- public float inverseB;
- }
-
- // Piecewise function indexed by value ranges.
- private readonly Dictionary m_PiecewiseFunctionMap = new Dictionary();
-
- static void ComputeTransformationParameters(float x0, float x1, float y0, float y1, out float m, out float b)
- {
- m = (y0 - y1) / (x0 - x1);
- b = (m * -x0) + y0;
- }
-
- static float DoTransformation(in float x, in float m, in float b) => (m * x) + b;
-
- // Ensure clamping to (0,1) as sometimes the function evaluates to slightly below 0 (breaking the handle).
- static float ValueToSlider(Piece p, float x) => Mathf.Clamp01(DoTransformation(x, p.inverseM, p.inverseB));
- static float SliderToValue(Piece p, float x) => DoTransformation(x, p.directM, p.directB);
-
- // Ideally we want a continuous, monotonically increasing function, but this is useful as we can easily fit a
- // distribution to a set of (huge) value ranges onto a slider.
- public PiecewiseLightUnitSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor)
- {
- // Sort the ranges into ascending order
- var sortedRanges = m_Descriptor.valueRanges.OrderBy(x => x.value.x).ToArray();
- var sliderDistribution = m_Descriptor.sliderDistribution;
-
- // Compute the transformation for each value range.
- for (int i = 0; i < sortedRanges.Length; i++)
- {
- var r = sortedRanges[i].value;
-
- var x0 = sliderDistribution[i + 0];
- var x1 = sliderDistribution[i + 1];
- var y0 = r.x;
- var y1 = r.y;
-
- Piece piece;
- piece.domain = new Vector2(x0, x1);
- piece.range = new Vector2(y0, y1);
-
- ComputeTransformationParameters(x0, x1, y0, y1, out piece.directM, out piece.directB);
-
- // Compute the inverse
- ComputeTransformationParameters(y0, y1, x0, x1, out piece.inverseM, out piece.inverseB);
-
- m_PiecewiseFunctionMap.Add(sortedRanges[i].value, piece);
- }
- }
-
- protected override float GetPositionOnSlider(float value, Vector2 valueRange)
- {
- if (!m_PiecewiseFunctionMap.TryGetValue(valueRange, out var piecewise))
- return -1f;
-
- return ValueToSlider(piecewise, value);
- }
-
- // Search for the corresponding piece-wise function to a value on the domain and update the input piece to it.
- // Returns true if search was successful and an update was made, false otherwise.
- bool UpdatePiece(ref Piece piece, float x)
- {
- foreach (var pair in m_PiecewiseFunctionMap)
- {
- var p = pair.Value;
-
- if (x >= p.domain.x && x <= p.domain.y)
- {
- piece = p;
-
- return true;
- }
- }
-
- return false;
- }
-
- void SliderOutOfBounds(Rect rect, ref float value)
- {
- EditorGUI.BeginChangeCheck();
- var internalValue = GUI.HorizontalSlider(rect, value, 0f, 1f);
- if (EditorGUI.EndChangeCheck())
- {
- Piece p = new Piece();
- UpdatePiece(ref p, internalValue);
- value = SliderToValue(p, internalValue);
- }
- }
-
- protected override void DoSlider(Rect rect, ref float value, Vector2 sliderRange, Vector2 valueRange)
- {
- // Map the internal slider value to the current piecewise function
- if (!m_PiecewiseFunctionMap.TryGetValue(valueRange, out var piece))
- {
- // Assume that if the piece is not found, that means the unit value is out of bounds.
- SliderOutOfBounds(rect, ref value);
- return;
- }
-
- // Maintain an internal value to support a single linear continuous function
- EditorGUI.BeginChangeCheck();
- var internalValue = GUI.HorizontalSlider(rect, ValueToSlider(piece, value), 0f, 1f);
- if (EditorGUI.EndChangeCheck())
- {
- // Ensure that the current function piece is being used to transform the value
- UpdatePiece(ref piece, internalValue);
- value = SliderToValue(piece, internalValue);
- }
- }
- }
-
- ///
- /// Formats the provided descriptor into a punctual light unit slider with contextual slider markers, tooltips, and icons.
- ///
- class PunctualLightUnitSlider : PiecewiseLightUnitSlider
- {
- public PunctualLightUnitSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor) { }
-
- private SerializedHDLight m_Light;
- private Editor m_Editor;
- private LightUnit m_Unit;
- private bool m_SpotReflectorEnabled;
-
- // Note: these should be in sync with LightUnit
- private static string[] k_UnitNames =
- {
- "Lumen",
- "Candela",
- "Lux",
- "Nits",
- "EV",
- };
-
- public void Setup(LightUnit unit, SerializedHDLight light, Editor owner)
- {
- m_Unit = unit;
- m_Light = light;
- m_Editor = owner;
-
- // Cache the spot reflector state as we will need to revert back to it after treating the slider as point light.
- m_SpotReflectorEnabled = light.enableSpotReflector.boolValue;
- }
-
- public override void Draw(Rect rect, SerializedProperty value, ref float floatValue)
- {
- // Convert the incoming unit value into Lumen as the punctual slider is always in these terms (internally)
- float convertedValue = UnitToLumen(floatValue);
-
- EditorGUI.BeginChangeCheck();
- base.Draw(rect, value, ref convertedValue);
- if (EditorGUI.EndChangeCheck())
- floatValue = LumenToUnit(convertedValue);
- }
-
- protected override GUIContent GetLightUnitTooltip(string baseTooltip, float value, string unit)
- {
- // Convert the internal lumens into the actual light unit value
- value = LumenToUnit(value);
- unit = k_UnitNames[(int)m_Unit];
-
- return base.GetLightUnitTooltip(baseTooltip, value, unit);
- }
-
- float UnitToLumen(float value)
- {
- if (m_Unit == LightUnit.Lumen)
- return value;
-
- // Punctual slider currently does not have any regard for spot shape/reflector.
- // Conversions need to happen as if light is a point, and this is the only setting that influences that.
- m_Light.enableSpotReflector.boolValue = false;
-
- return HDLightUI.ConvertLightIntensity(m_Unit, LightUnit.Lumen, m_Light, m_Editor, value);
- }
-
- float LumenToUnit(float value)
- {
- if (m_Unit == LightUnit.Lumen)
- return value;
-
- // Once again temporarily disable reflector in case we called this for tooltip or context menu preset.
- m_Light.enableSpotReflector.boolValue = false;
-
- value = HDLightUI.ConvertLightIntensity(LightUnit.Lumen, m_Unit, m_Light, m_Editor, value);
-
- // Restore the state of spot reflector on the light.
- m_Light.enableSpotReflector.boolValue = m_SpotReflectorEnabled;
-
- return value;
- }
-
- protected override void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
- {
- m_Light?.Update();
-
- // Convert to the actual unit value.
- value.floatValue = LumenToUnit(preset.presetValue);
-
- m_Light?.Apply();
- }
- }
-
- ///
- /// Formats the provided descriptor into a temperature unit slider with contextual slider markers, tooltips, and icons.
- ///
- class TemperatureSlider : LightUnitSlider
- {
- private Vector3 m_ExponentialConstraints;
-
- private LightEditor.Settings m_Settings;
-
- private static Texture2D s_KelvinGradientTexture;
-
- ///
- /// Exponential slider modeled to set a f(0.5) value.
- /// ref: https://stackoverflow.com/a/17102320
- ///
- void PrepareExponentialConstraints(float lo, float mi, float hi)
- {
- // float x = lo;
- // float y = mi;
- // float z = hi;
- //
- // // https://www.desmos.com/calculator/yx2yf4huia
- // m_ExponentialConstraints.x = ((x * z) - (y * y)) / (x - (2 * y) + z);
- // m_ExponentialConstraints.y = ((y - x) * (y - x)) / (x - (2 * y) + z);
- // m_ExponentialConstraints.z = 2 * Mathf.Log((z - y) / (y - x));
-
- // Warning: These are the coefficients for a system of equation fit for a continuous, monotonic curve that fits a f(0.44) value.
- // f(0.44) is required instead of f(0.5) due to the location of the white in the temperature gradient texture.
- // The equation is solved to get the coefficient for the following constraint for low, mid, hi:
- // f(0) = 1500
- // f(0.44) = 6500
- // f(1.0) = 20000
- // If for any reason the constraints are changed, then the function must be refit and the new coefficients found.
- // Note that we can't re-use the original PowerSlider instead due to how it forces a text field, which we don't want in this case.
- m_ExponentialConstraints.x = -3935.53965427f;
- m_ExponentialConstraints.y = 5435.53965427f;
- m_ExponentialConstraints.z = 1.48240556f;
- }
-
- protected float ValueToSlider(float x) => Mathf.Log((x - m_ExponentialConstraints.x) / m_ExponentialConstraints.y) / m_ExponentialConstraints.z;
- protected float SliderToValue(float x) => m_ExponentialConstraints.x + m_ExponentialConstraints.y * Mathf.Exp(m_ExponentialConstraints.z * x);
-
- protected override float GetPositionOnSlider(float value, Vector2 valueRange)
- {
- return ValueToSlider(value);
- }
-
- static Texture2D GetKelvinGradientTexture(LightEditor.Settings settings)
- {
- if (s_KelvinGradientTexture == null)
- {
- var kelvinTexture = (Texture2D)typeof(LightEditor.Settings).GetField("m_KelvinGradientTexture", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(settings);
-
- // This seems to be the only way to gamma-correct the internal gradient tex (aside from drawing it manually).
- var kelvinTextureLinear = new Texture2D(kelvinTexture.width, kelvinTexture.height, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.MipChain);
- kelvinTextureLinear.SetPixels(kelvinTexture.GetPixels());
- kelvinTextureLinear.Apply();
-
- s_KelvinGradientTexture = kelvinTextureLinear;
- }
-
- return s_KelvinGradientTexture;
- }
-
- public TemperatureSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor)
- {
- var halfValue = 6500;
- PrepareExponentialConstraints(m_Descriptor.sliderRange.x, halfValue, m_Descriptor.sliderRange.y);
- }
-
- public void Setup(LightEditor.Settings settings)
- {
- m_Settings = settings;
- }
-
- // The serialized property for color temperature is stored in the build-in light editor, and we need to use this object to apply the update.
- protected override void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
- {
- m_Settings.Update();
-
- base.SetValueToPreset(value, preset);
-
- m_Settings.ApplyModifiedProperties();
- }
-
- protected override void DoSlider(Rect rect, ref float value, Vector2 sliderRange)
- {
- SliderWithTextureNoTextField(rect, ref value, sliderRange, m_Settings);
- }
-
- // Note: We could use the internal SliderWithTexture, however: the internal slider func forces a text-field (and no ability to opt-out of it).
- void SliderWithTextureNoTextField(Rect rect, ref float value, Vector2 range, LightEditor.Settings settings)
- {
- GUI.DrawTexture(rect, GetKelvinGradientTexture(settings));
-
- EditorGUI.BeginChangeCheck();
-
- // Draw the exponential slider that fits 6500K to the white point on the gradient texture.
- var internalValue = GUI.HorizontalSlider(rect, ValueToSlider(value), 0f, 1f, SliderStyles.k_TemperatureBorder, SliderStyles.k_TemperatureThumb);
-
- // Round to nearest since so much precision is not necessary for kelvin while sliding.
- if (EditorGUI.EndChangeCheck())
- {
- // Map the value back into kelvin.
- value = SliderToValue(internalValue);
-
- value = Mathf.Round(value);
- }
- }
- }
-
internal class LightUnitSliderUIDrawer
{
- static PiecewiseLightUnitSlider k_DirectionalLightUnitSlider;
- static PunctualLightUnitSlider k_PunctualLightUnitSlider;
- static PiecewiseLightUnitSlider k_ExposureSlider;
- static TemperatureSlider k_TemperatureSlider;
+ static HDPiecewiseLightUnitSlider k_DirectionalLightUnitSlider;
+ static HDPunctualLightUnitSlider k_PunctualLightUnitSlider;
+ static HDPiecewiseLightUnitSlider k_ExposureSlider;
static LightUnitSliderUIDrawer()
{
// Maintain a unique slider for directional/lux.
- k_DirectionalLightUnitSlider = new PiecewiseLightUnitSlider(LightUnitSliderDescriptors.LuxDescriptor);
+ k_DirectionalLightUnitSlider = new HDPiecewiseLightUnitSlider(LightUnitSliderDescriptors.LuxDescriptor);
// Internally, slider is always in terms of lumens, so that the slider is uniform for all light units.
- k_PunctualLightUnitSlider = new PunctualLightUnitSlider(LightUnitSliderDescriptors.LumenDescriptor);
+ k_PunctualLightUnitSlider = new HDPunctualLightUnitSlider(LightUnitSliderDescriptors.LumenDescriptor);
// Exposure is in EV100, but we load a separate due to the different icon set.
- k_ExposureSlider = new PiecewiseLightUnitSlider(LightUnitSliderDescriptors.ExposureDescriptor);
-
- // Kelvin is not classified internally as a light unit so we handle it independently as well.
- k_TemperatureSlider = new TemperatureSlider(LightUnitSliderDescriptors.TemperatureDescriptor);
+ k_ExposureSlider = new HDPiecewiseLightUnitSlider(LightUnitSliderDescriptors.ExposureDescriptor);
}
// Need to cache the serialized object on the slider, to add support for the preset selection context menu (need to apply changes to serialized)
@@ -608,7 +279,6 @@ public void SetSerializedObject(SerializedObject serializedObject)
k_DirectionalLightUnitSlider.SetSerializedObject(serializedObject);
k_PunctualLightUnitSlider.SetSerializedObject(serializedObject);
k_ExposureSlider.SetSerializedObject(serializedObject);
- k_TemperatureSlider.SetSerializedObject(serializedObject);
}
public void Draw(HDLightType type, LightUnit lightUnit, SerializedProperty value, Rect rect, SerializedHDLight light, Editor owner)
@@ -650,18 +320,5 @@ public void DrawExposureSlider(SerializedProperty value, Rect rect)
value.floatValue = val;
}
}
-
- public void DrawTemperatureSlider(LightEditor.Settings settings, SerializedProperty value, Rect rect)
- {
- using (new EditorGUI.IndentLevelScope(-EditorGUI.indentLevel))
- {
- k_TemperatureSlider.Setup(settings);
-
- float val = value.floatValue;
- k_TemperatureSlider.Draw(rect, value, ref val);
- if (val != value.floatValue)
- value.floatValue = val;
- }
- }
}
}
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/TemperatureSlider.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/TemperatureSlider.cs
new file mode 100644
index 00000000000..1f1997643fc
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/TemperatureSlider.cs
@@ -0,0 +1,144 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Rendering.HighDefinition;
+using UnityEngine.Experimental.Rendering;
+
+namespace UnityEditor.Rendering.HighDefinition
+{
+ ///
+ /// Formats the provided descriptor into a temperature unit slider with contextual slider markers, tooltips, and icons.
+ ///
+ class TemperatureSlider : LightUnitSlider
+ {
+ private Vector3 m_ExponentialConstraints;
+
+ private LightEditor.Settings m_Settings;
+
+ private static Texture2D s_KelvinGradientTexture;
+
+ ///
+ /// Exponential slider modeled to set a f(0.5) value.
+ /// ref: https://stackoverflow.com/a/17102320
+ ///
+ void PrepareExponentialConstraints(float lo, float mi, float hi)
+ {
+ // float x = lo;
+ // float y = mi;
+ // float z = hi;
+ //
+ // // https://www.desmos.com/calculator/yx2yf4huia
+ // m_ExponentialConstraints.x = ((x * z) - (y * y)) / (x - (2 * y) + z);
+ // m_ExponentialConstraints.y = ((y - x) * (y - x)) / (x - (2 * y) + z);
+ // m_ExponentialConstraints.z = 2 * Mathf.Log((z - y) / (y - x));
+
+ // Warning: These are the coefficients for a system of equation fit for a continuous, monotonic curve that fits a f(0.44) value.
+ // f(0.44) is required instead of f(0.5) due to the location of the white in the temperature gradient texture.
+ // The equation is solved to get the coefficient for the following constraint for low, mid, hi:
+ // f(0) = 1500
+ // f(0.44) = 6500
+ // f(1.0) = 20000
+ // If for any reason the constraints are changed, then the function must be refit and the new coefficients found.
+ // Note that we can't re-use the original PowerSlider instead due to how it forces a text field, which we don't want in this case.
+ m_ExponentialConstraints.x = -3935.53965427f;
+ m_ExponentialConstraints.y = 5435.53965427f;
+ m_ExponentialConstraints.z = 1.48240556f;
+ }
+
+ protected float ValueToSlider(float x) => Mathf.Log((x - m_ExponentialConstraints.x) / m_ExponentialConstraints.y) / m_ExponentialConstraints.z;
+ protected float SliderToValue(float x) => m_ExponentialConstraints.x + m_ExponentialConstraints.y * Mathf.Exp(m_ExponentialConstraints.z * x);
+
+ protected override float GetPositionOnSlider(float value, Vector2 valueRange)
+ {
+ return ValueToSlider(value);
+ }
+
+ static Texture2D GetKelvinGradientTexture(LightEditor.Settings settings)
+ {
+ if (s_KelvinGradientTexture == null)
+ {
+ var kelvinTexture = (Texture2D)typeof(LightEditor.Settings).GetField("m_KelvinGradientTexture", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(settings);
+
+ // This seems to be the only way to gamma-correct the internal gradient tex (aside from drawing it manually).
+ var kelvinTextureLinear = new Texture2D(kelvinTexture.width, kelvinTexture.height, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.MipChain);
+ kelvinTextureLinear.SetPixels(kelvinTexture.GetPixels());
+ kelvinTextureLinear.Apply();
+
+ s_KelvinGradientTexture = kelvinTextureLinear;
+ }
+
+ return s_KelvinGradientTexture;
+ }
+
+ public TemperatureSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor)
+ {
+ var halfValue = 6500;
+ PrepareExponentialConstraints(m_Descriptor.sliderRange.x, halfValue, m_Descriptor.sliderRange.y);
+ }
+
+ public void Setup(LightEditor.Settings settings)
+ {
+ m_Settings = settings;
+ }
+
+ // The serialized property for color temperature is stored in the build-in light editor, and we need to use this object to apply the update.
+ protected override void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
+ {
+ m_Settings.Update();
+
+ base.SetValueToPreset(value, preset);
+
+ m_Settings.ApplyModifiedProperties();
+ }
+
+ protected override void DoSlider(Rect rect, ref float value, Vector2 sliderRange)
+ {
+ SliderWithTextureNoTextField(rect, ref value, sliderRange, m_Settings);
+ }
+
+ // Note: We could use the internal SliderWithTexture, however: the internal slider func forces a text-field (and no ability to opt-out of it).
+ void SliderWithTextureNoTextField(Rect rect, ref float value, Vector2 range, LightEditor.Settings settings)
+ {
+ GUI.DrawTexture(rect, GetKelvinGradientTexture(settings));
+
+ EditorGUI.BeginChangeCheck();
+
+ // Draw the exponential slider that fits 6500K to the white point on the gradient texture.
+ var internalValue = GUI.HorizontalSlider(rect, ValueToSlider(value), 0f, 1f, SliderStyles.k_TemperatureBorder, SliderStyles.k_TemperatureThumb);
+
+ // Round to nearest since so much precision is not necessary for kelvin while sliding.
+ if (EditorGUI.EndChangeCheck())
+ {
+ // Map the value back into kelvin.
+ value = SliderToValue(internalValue);
+
+ value = Mathf.Round(value);
+ }
+ }
+ }
+
+ internal class TemperatureSliderUIDrawer
+ {
+ static TemperatureSlider k_TemperatureSlider;
+
+ static TemperatureSliderUIDrawer()
+ {
+ // Kelvin is not classified internally as a light unit so we handle it independently as well.
+ k_TemperatureSlider = new TemperatureSlider(LightUnitSliderDescriptors.TemperatureDescriptor);
+ }
+
+ public static void Draw(LightEditor.Settings settings, SerializedObject serializedObject, SerializedProperty value, Rect rect)
+ {
+ k_TemperatureSlider.SetSerializedObject(serializedObject);
+ using (new EditorGUI.IndentLevelScope(-EditorGUI.indentLevel))
+ {
+ k_TemperatureSlider.Setup(settings);
+
+ float val = value.floatValue;
+ k_TemperatureSlider.Draw(rect, value, ref val);
+ if (val != value.floatValue)
+ value.floatValue = val;
+ }
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/TemperatureSlider.cs.meta b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/TemperatureSlider.cs.meta
new file mode 100644
index 00000000000..63fd33f4d99
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/LightUnit/TemperatureSlider.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 33d6ef6a49896aa44a810a84e3cd394f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: