using System; namespace UnityEngine.Rendering.PostProcessing { /// /// The base abstract class for all parameter override types. /// /// public abstract class ParameterOverride { /// /// The override state of this parameter. /// public bool overrideState; internal abstract void Interp(ParameterOverride from, ParameterOverride to, float t); /// /// Returns the computed hash code for this parameter. /// /// A computed hash code public abstract int GetHash(); /// /// Casts and returns the value stored in this parameter. /// /// The type to cast to /// The value stored in this parameter public T GetValue() { return ((ParameterOverride)this).value; } /// /// This method is called right after the parent has /// been initialized. This is used in case you need to access fields or properties that /// can't be accessed in the constructor of a /// (ParameterOverride objects are generally declared and initialized in a /// ). /// /// protected internal virtual void OnEnable() { } /// /// This method is called right before the parent /// gets de-initialized. /// /// protected internal virtual void OnDisable() { } internal abstract void SetValue(ParameterOverride parameter); } /// /// The base typed class for all parameter override types. /// /// The type of value to store in this ParameterOverride /// /// Due to limitations with the serialization system in Unity you shouldn't use this class /// directly. Use one of the pre-flatten types (like or make your /// own by extending this class. /// /// /// This sample code shows how to make a custom parameter holding a float. /// /// [Serializable] /// public sealed class FloatParameter : ParameterOverride<float> /// { /// public override void Interp(float from, float to, float t) /// { /// value = from + (to - from) * t; /// } /// } /// /// [Serializable] public class ParameterOverride : ParameterOverride { /// /// The value stored in this parameter. /// public T value; /// /// Creates a ParameterOverride with a default and /// set to false. /// public ParameterOverride() : this(default(T), false) { } /// /// Creates a ParameterOverride with a given value and /// set to false. /// /// The value to set this parameter to public ParameterOverride(T value) : this(value, false) { } /// /// Creates a ParameterOverride with a given value and override state. /// /// The value to set this parameter to /// The override state for this value public ParameterOverride(T value, bool overrideState) { this.value = value; this.overrideState = overrideState; } internal override void Interp(ParameterOverride from, ParameterOverride to, float t) { // Note: this isn't completely safe but it'll do fine Interp(from.GetValue(), to.GetValue(), t); } /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public virtual void Interp(T from, T to, float t) { // Returns `to` if `dt > 0` by default so we don't have to write overrides for bools and // enumerations. value = t > 0f ? to : from; } /// /// Sets the value for this parameter to and mark the override state /// to true. /// /// public void Override(T x) { overrideState = true; value = x; } internal override void SetValue(ParameterOverride parameter) { value = parameter.GetValue(); } /// /// Returns the computed hash code for this parameter. /// /// A computed hash code public override int GetHash() { unchecked { int hash = 17; hash = hash * 23 + overrideState.GetHashCode(); hash = hash * 23 + value.GetHashCode(); return hash; } } /// /// Implicit conversion between and its value type. /// /// The parameter to implicitly cast /// A value of type . public static implicit operator T(ParameterOverride prop) { return prop.value; } } // Bypassing the limited unity serialization system... /// /// A that holds a float value. /// /// /// The interpolation method for this parameter is the same as . /// [Serializable] public sealed class FloatParameter : ParameterOverride { /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(float from, float to, float t) { value = from + (to - from) * t; } } /// /// A that holds a int value. /// /// /// The interpolation method for this parameter is the same as /// casted to int. /// [Serializable] public sealed class IntParameter : ParameterOverride { /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(int from, int to, float t) { // Int snapping interpolation. Don't use this for enums as they don't necessarily have // contiguous values. Use the default interpolator instead (same as bool). value = (int)(from + (to - from) * t); } } /// /// A that holds a bool value. /// [Serializable] public sealed class BoolParameter : ParameterOverride { } /// /// A that holds a value. /// /// /// The interpolation method for this parameter is the same as /// for each channel. /// [Serializable] public sealed class ColorParameter : ParameterOverride { /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(Color from, Color to, float t) { // Lerping color values is a sensitive subject... We looked into lerping colors using // HSV and LCH but they have some downsides that make them not work correctly in all // situations, so we stick with RGB lerping for now, at least its behavior is // predictable despite looking desaturated when `t ~= 0.5` and it's faster anyway. value.r = from.r + (to.r - from.r) * t; value.g = from.g + (to.g - from.g) * t; value.b = from.b + (to.b - from.b) * t; value.a = from.a + (to.a - from.a) * t; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector4. public static implicit operator Vector4(ColorParameter prop) { return prop.value; } } /// /// A that holds a value. /// /// /// The interpolation method for this parameter is the same as /// for each axis. /// [Serializable] public sealed class Vector2Parameter : ParameterOverride { /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(Vector2 from, Vector2 to, float t) { value.x = from.x + (to.x - from.x) * t; value.y = from.y + (to.y - from.y) * t; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector3. public static implicit operator Vector3(Vector2Parameter prop) { return prop.value; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector4. public static implicit operator Vector4(Vector2Parameter prop) { return prop.value; } } /// /// A that holds a value. /// /// /// The interpolation method for this parameter is the same as /// for each axis. /// [Serializable] public sealed class Vector3Parameter : ParameterOverride { /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(Vector3 from, Vector3 to, float t) { value.x = from.x + (to.x - from.x) * t; value.y = from.y + (to.y - from.y) * t; value.z = from.z + (to.z - from.z) * t; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector2. public static implicit operator Vector2(Vector3Parameter prop) { return prop.value; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector4. public static implicit operator Vector4(Vector3Parameter prop) { return prop.value; } } /// /// A that holds a value. /// /// /// The interpolation method for this parameter is the same as /// for each axis. /// [Serializable] public sealed class Vector4Parameter : ParameterOverride { /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(Vector4 from, Vector4 to, float t) { value.x = from.x + (to.x - from.x) * t; value.y = from.y + (to.y - from.y) * t; value.z = from.z + (to.z - from.z) * t; value.w = from.w + (to.w - from.w) * t; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector2. public static implicit operator Vector2(Vector4Parameter prop) { return prop.value; } /// /// Implicit conversion between and a . /// /// The parameter to implicitly cast /// A Vector3. public static implicit operator Vector3(Vector4Parameter prop) { return prop.value; } } /// /// A that holds a value. /// /// /// The interpolation method for this parameter is the same as /// for each point on the curve. /// [Serializable] public sealed class SplineParameter : ParameterOverride { /// /// This method is called right after the parent has /// been initialized. This is used in case you need to access fields or properties that /// can't be accessed in the constructor of a /// (ParameterOverride objects are generally declared and initialized in a /// ). /// /// protected internal override void OnEnable() { if (value != null) value.Cache(int.MinValue); } internal override void SetValue(ParameterOverride parameter) { base.SetValue(parameter); if (value != null) value.Cache(Time.renderedFrameCount); } /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(Spline from, Spline to, float t) { if (from == null || to == null) { base.Interp(from, to, t); return; } int frameCount = Time.renderedFrameCount; from.Cache(frameCount); to.Cache(frameCount); for (int i = 0; i < Spline.k_Precision; i++) { float a = from.cachedData[i]; float b = to.cachedData[i]; value.cachedData[i] = a + (b - a) * t; } } } /// /// A set of default textures to use as default values for . /// public enum TextureParameterDefault { /// /// No texture, or null. /// None, /// /// A black texture. /// Black, /// /// A white texture. /// White, /// /// A transparent texture. /// Transparent, /// /// A 2D lookup table in strip format with width = height * height. /// Lut2D } /// /// A that holds a value. /// /// /// Texture interpolation is done using a classic linear interpolation method. /// [Serializable] public sealed class TextureParameter : ParameterOverride { /// The default state & type for the texture. public TextureParameterDefault defaultState = TextureParameterDefault.Black; /// /// Interpolates between two values given an interpolation factor . /// /// The value to interpolate from /// The value to interpolate to /// An interpolation factor (generally in range [0,1]) /// /// By default this method does a "snap" interpolation, meaning it will return the value /// if is higher than 0, /// otherwise. /// public override void Interp(Texture from, Texture to, float t) { // Both are null, do nothing if (from == null && to == null) { value = null; return; } // Both aren't null we're ready to blend if (from != null && to != null) { value = TextureLerper.instance.Lerp(from, to, t); return; } // One of them is null, blend to/from a default value is applicable { if (defaultState == TextureParameterDefault.Lut2D) { int size = from != null ? from.height : to.height; Texture defaultTexture = RuntimeUtilities.GetLutStrip(size); if (from == null) from = defaultTexture; if (to == null) to = defaultTexture; } Color tgtColor; switch (defaultState) { case TextureParameterDefault.Black: tgtColor = Color.black; break; case TextureParameterDefault.White: tgtColor = Color.white; break; case TextureParameterDefault.Transparent: tgtColor = Color.clear; break; case TextureParameterDefault.Lut2D: { // Find the current lut size int size = from != null ? from.height : to.height; Texture defaultTexture = RuntimeUtilities.GetLutStrip(size); if (from == null) from = defaultTexture; if (to == null) to = defaultTexture; // Fail safe in case the lut size is incorrect if (from.width != to.width || from.height != to.height) { value = null; return; } value = TextureLerper.instance.Lerp(from, to, t); // All done, return return; } default: // defaultState is none, so just interpolate the base and return base.Interp(from, to, t); return; } // If we made it this far, tgtColor contains the color we'll be lerping into (or out of) if (from == null) { // color -> texture lerp, invert ratio value = TextureLerper.instance.Lerp(to, tgtColor, 1f - t); } else { value = TextureLerper.instance.Lerp(from, tgtColor, t); } } } } }