154 lines
6.7 KiB
C#
154 lines
6.7 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Experimental.Rendering;
|
|
|
|
namespace UnityEditor.Rendering
|
|
{
|
|
/// <summary>
|
|
/// Formats the provided descriptor into a temperature unit slider with contextual slider markers, tooltips, and icons.
|
|
/// </summary>
|
|
class TemperatureSlider : LightUnitSlider
|
|
{
|
|
private Vector3 m_ExponentialConstraints;
|
|
|
|
private LightEditor.Settings m_Settings;
|
|
|
|
private static Texture2D s_KelvinGradientTexture;
|
|
|
|
/// <summary>
|
|
/// Exponential slider modeled to set a f(0.5) value.
|
|
/// ref: https://stackoverflow.com/a/17102320
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper to draw a temperature slider on the inspector
|
|
/// </summary>
|
|
public 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws a temperature slider
|
|
/// </summary>
|
|
/// <param name="settings">The light settings</param>
|
|
/// <param name="serializedObject">The serialized object</param>
|
|
/// <param name="value">The serialized property</param>
|
|
/// <param name="rect">The rect where the slider will be drawn</param>
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|