Singularity/Library/PackageCache/com.unity.render-pipelines..../Editor/Lighting/LightUnit/TemperatureSlider.cs

154 lines
6.7 KiB
C#
Raw Normal View History

2024-05-06 14:45:45 -04:00
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;
}
}
}
}