123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- using System;
- using System.Runtime.CompilerServices;
- using UnityEngine.Experimental.Rendering;
-
- namespace UnityEngine.Rendering
- {
- // Due to limitations in the builtin Gradient we need this custom wrapper.
-
- /// <summary>
- /// A wrapper around <c>Gradient</c> to automatically bake it into a texture.
- /// </summary>
- [Serializable]
- public class TextureGradient : IDisposable
- {
- /// <summary>
- /// Texture Size computed.
- /// </summary>
- [field: SerializeField, HideInInspector]
- public int textureSize { get; private set; }
-
- /// <summary>
- /// Internal Gradient used to generate the Texture
- /// </summary>
- [SerializeField]
- Gradient m_Gradient;
-
- Texture2D m_Texture = null;
-
- int m_RequestedTextureSize = -1;
-
- bool m_IsTextureDirty;
- bool m_Precise;
-
- /// <summary>All color keys defined in the gradient.</summary>
- [HideInInspector]
- public GradientColorKey[] colorKeys => m_Gradient?.colorKeys;
-
- /// <summary>All alpha keys defined in the gradient.</summary>
- [HideInInspector]
- public GradientAlphaKey[] alphaKeys => m_Gradient?.alphaKeys;
-
- /// <summary>Controls how the gradient colors are interpolated.</summary>
- [SerializeField, HideInInspector]
- public GradientMode mode = GradientMode.PerceptualBlend;
-
- /// <summary>Indicates the color space that the gradient color keys are using.</summary>
- [SerializeField, HideInInspector]
- public ColorSpace colorSpace = ColorSpace.Uninitialized;
-
- /// <summary>
- /// Creates a new <see cref="TextureGradient"/> from an existing <c>Gradient</c>.
- /// </summary>
- /// <param name="baseCurve">The source <c>Gradient</c>.</param>
- public TextureGradient(Gradient baseCurve)
- : this(baseCurve.colorKeys, baseCurve.alphaKeys)
- {
- mode = baseCurve.mode;
- colorSpace = baseCurve.colorSpace;
- m_Gradient.mode = baseCurve.mode;
- m_Gradient.colorSpace = baseCurve.colorSpace;
- }
-
- /// <summary>
- /// Creates a new <see cref="TextureCurve"/> from an arbitrary number of keyframes.
- /// </summary>
- /// <param name="colorKeys">An array of keyframes used to define the color of gradient.</param>
- /// <param name="alphaKeys">An array of keyframes used to define the alpha of gradient.</param>
- /// <param name="mode">Indicates the color space that the gradient color keys are using.</param>
- /// <param name="colorSpace">Controls how the gradient colors are interpolated.</param>
- /// <param name="requestedTextureSize">Texture Size used internally, if '-1' using Nyquist-Shannon limits.</param>
- /// <param name="precise">if precise uses 4*Nyquist-Shannon limits, 2* otherwise.</param>
- public TextureGradient(GradientColorKey[] colorKeys, GradientAlphaKey[] alphaKeys, GradientMode mode = GradientMode.PerceptualBlend, ColorSpace colorSpace = ColorSpace.Uninitialized, int requestedTextureSize = -1, bool precise = false)
- {
- Rebuild(colorKeys, alphaKeys, mode, colorSpace, requestedTextureSize, precise);
- }
-
- void Rebuild(GradientColorKey[] colorKeys, GradientAlphaKey[] alphaKeys, GradientMode mode, ColorSpace colorSpace, int requestedTextureSize, bool precise)
- {
- m_Gradient = new Gradient();
- m_Gradient.mode = mode;
- m_Gradient.colorSpace = colorSpace;
- m_Gradient.SetKeys(colorKeys, alphaKeys);
- m_Precise = precise;
- m_RequestedTextureSize = requestedTextureSize;
- if (requestedTextureSize > 0)
- {
- textureSize = requestedTextureSize;
- }
- else
- {
- float smallestDelta = 1.0f;
- float[] times = new float[colorKeys.Length + alphaKeys.Length];
- for (int i = 0; i < colorKeys.Length; ++i)
- {
- times[i] = colorKeys[i].time;
- }
- for (int i = 0; i < alphaKeys.Length; ++i)
- {
- times[colorKeys.Length + i] = alphaKeys[i].time;
- }
- Array.Sort(times);
- // Found the smallest increment between 2 keys
- for (int i = 1; i < times.Length; ++i)
- {
- int k0 = Math.Max(i - 1, 0);
- int k1 = Math.Min(i, times.Length - 1);
- float delta = Mathf.Abs(times[k0] - times[k1]);
- // Do not compare if time is duplicated
- if (delta > 0 && delta < smallestDelta)
- smallestDelta = delta;
- }
-
- // Nyquist-Shannon
- // smallestDelta: 1.00f => Sampling => 2
- // smallestDelta: 0.50f => Sampling => 3
- // smallestDelta: 0.33f => Sampling => 4
- // smallestDelta: 0.25f => Sampling => 5
-
- // 2x: Theoretical limits
- // 4x: Preserve original frequency
-
- // Round to the closest 4 * Nyquist-Shannon limits
- // 4x for Fixed to capture sharp discontinuity
- float scale;
- if (precise || mode == GradientMode.Fixed)
- scale = 4.0f;
- else
- scale = 2.0f;
- float sizef = scale * Mathf.Ceil(1.0f / smallestDelta + 1.0f);
- textureSize = Mathf.RoundToInt(sizef);
- // Arbitrary max (1024)
- textureSize = Math.Min(textureSize, 1024);
- }
-
- SetDirty();
- }
-
- /// <summary>
- /// Cleans up the internal texture resource.
- /// </summary>
- public void Dispose()
- {
- //Release();
- }
-
- /// <summary>
- /// Releases the internal texture resource.
- /// </summary>
- public void Release()
- {
- if (m_Texture != null)
- CoreUtils.Destroy(m_Texture);
- m_Texture = null;
- }
-
- /// <summary>
- /// Marks the curve as dirty to trigger a redraw of the texture the next time <see cref="GetTexture"/>
- /// is called.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void SetDirty()
- {
- m_IsTextureDirty = true;
- }
-
- static GraphicsFormat GetTextureFormat()
- {
- return GraphicsFormat.R8G8B8A8_UNorm;
- }
-
- /// <summary>
- /// Gets the texture representation of this Gradient.
- /// </summary>
- /// <returns>A texture.</returns>
- public Texture2D GetTexture()
- {
- float step = 1.0f / (float)(textureSize - 1);
-
- if (m_Texture != null && m_Texture.width != textureSize)
- {
- Object.DestroyImmediate(m_Texture);
- m_Texture = null;
- }
-
- if (m_Texture == null)
- {
- m_Texture = new Texture2D(textureSize, 1, GetTextureFormat(), TextureCreationFlags.None);
- m_Texture.name = "GradientTexture";
- m_Texture.hideFlags = HideFlags.HideAndDontSave;
- m_Texture.filterMode = FilterMode.Bilinear;
- m_Texture.wrapMode = TextureWrapMode.Clamp;
- m_Texture.anisoLevel = 0;
- m_IsTextureDirty = true;
- }
-
- if (m_IsTextureDirty)
- {
- var pixels = new Color[textureSize];
-
- for (int i = 0; i < textureSize; i++)
- pixels[i] = Evaluate(i * step);
-
- m_Texture.SetPixels(pixels);
- m_Texture.Apply(false, false);
- m_IsTextureDirty = false;
- m_Texture.IncrementUpdateCount();
- }
-
- return m_Texture;
- }
-
- /// <summary>
- /// Evaluate a time value on the Gradient.
- /// </summary>
- /// <param name="time">The time within the Gradient you want to evaluate.</param>
- /// <returns>The value of the Gradient, at the point in time specified.</returns>
- public Color Evaluate(float time)
- {
- if (textureSize <= 0)
- return Color.black;
-
- return m_Gradient.Evaluate(time);
- }
-
-
- /// <summary>
- /// Setup Gradient with an array of color keys and alpha keys.
- /// </summary>
- /// <param name="colorKeys">Color keys of the gradient (maximum 8 color keys).</param>
- /// <param name="alphaKeys">Alpha keys of the gradient (maximum 8 alpha keys).</param>
- /// <param name="mode">Indicates the color space that the gradient color keys are using.</param>
- /// <param name="colorSpace">Controls how the gradient colors are interpolated.</param>
- public void SetKeys(GradientColorKey[] colorKeys, GradientAlphaKey[] alphaKeys, GradientMode mode, ColorSpace colorSpace)
- {
- m_Gradient.SetKeys(colorKeys, alphaKeys);
- m_Gradient.mode = mode;
- m_Gradient.colorSpace = colorSpace;
- // Rebuild will make the TextureGradient Dirty.
- Rebuild(colorKeys, alphaKeys, mode, colorSpace, m_RequestedTextureSize, m_Precise);
- }
- }
-
- /// <summary>
- /// A <see cref="VolumeParameter"/> that holds a <see cref="TextureGradient"/> value.
- /// </summary>
- [Serializable]
- public class TextureGradientParameter : VolumeParameter<TextureGradient>
- {
- /// <summary>
- /// Creates a new <see cref="TextureGradientParameter"/> instance.
- /// </summary>
- /// <param name="value">The initial value to store in the parameter.</param>
- /// <param name="overrideState">The initial override state for the parameter.</param>
- public TextureGradientParameter(TextureGradient value, bool overrideState = false)
- : base(value, overrideState) { }
-
- /// <summary>
- /// Release implementation.
- /// </summary>
- public override void Release() => m_Value.Release();
-
- // TODO: TextureGradient interpolation
- }
- }
|