VolumeComponent.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Reflection;
  5. using System.Linq;
  6. namespace UnityEngine.Rendering
  7. {
  8. /// <summary>
  9. /// This attribute allows you to add commands to the <strong>Add Override</strong> popup menu
  10. /// on Volumes.
  11. /// </summary>
  12. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
  13. public sealed class VolumeComponentMenu : Attribute
  14. {
  15. /// <summary>
  16. /// The name of the entry in the override list. You can use slashes to create sub-menus.
  17. /// </summary>
  18. public readonly string menu;
  19. // TODO: Add support for component icons
  20. /// <summary>
  21. /// Creates a new <seealso cref="VolumeComponentMenu"/> instance.
  22. /// </summary>
  23. /// <param name="menu">The name of the entry in the override list. You can use slashes to
  24. /// create sub-menus.</param>
  25. public VolumeComponentMenu(string menu)
  26. {
  27. this.menu = menu;
  28. }
  29. }
  30. /// <summary>
  31. /// An attribute set on deprecated volume components.
  32. /// </summary>
  33. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
  34. public sealed class VolumeComponentDeprecated : Attribute
  35. {
  36. }
  37. /// <summary>
  38. /// The base class for all the components that can be part of a <see cref="VolumeProfile"/>.
  39. /// The Volume framework automatically handles and interpolates any <see cref="VolumeParameter"/> members found in this class.
  40. /// </summary>
  41. /// <example>
  42. /// <code>
  43. /// using UnityEngine.Rendering;
  44. ///
  45. /// [Serializable, VolumeComponentMenu("Custom/Example Component")]
  46. /// public class ExampleComponent : VolumeComponent
  47. /// {
  48. /// public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
  49. /// }
  50. /// </code>
  51. /// </example>
  52. [Serializable]
  53. public class VolumeComponent : ScriptableObject
  54. {
  55. /// <summary>
  56. /// The active state of the set of parameters defined in this class. You can use this to
  57. /// quickly turn on or off all the overrides at once.
  58. /// </summary>
  59. public bool active = true;
  60. /// <summary>
  61. /// The name displayed in the component header. If you do not set a name, Unity generates one from
  62. /// the class name automatically.
  63. /// </summary>
  64. public string displayName { get; protected set; } = "";
  65. /// <summary>
  66. /// A read-only collection of all the <see cref="VolumeParameter"/>s defined in this class.
  67. /// </summary>
  68. public ReadOnlyCollection<VolumeParameter> parameters { get; private set; }
  69. #pragma warning disable 414
  70. [SerializeField]
  71. bool m_AdvancedMode = false; // Editor-only
  72. #pragma warning restore 414
  73. /// <summary>
  74. /// Unity calls this method when it loads the class.
  75. /// </summary>
  76. /// <remarks>
  77. /// If you want to override this method, you must call <c>base.OnEnable()</c>.
  78. /// </remarks>
  79. protected virtual void OnEnable()
  80. {
  81. // Automatically grab all fields of type VolumeParameter for this instance
  82. parameters = this.GetType()
  83. .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  84. .Where(t => t.FieldType.IsSubclassOf(typeof(VolumeParameter)))
  85. .OrderBy(t => t.MetadataToken) // Guaranteed order
  86. .Select(t => (VolumeParameter)t.GetValue(this))
  87. .ToList()
  88. .AsReadOnly();
  89. foreach (var parameter in parameters)
  90. parameter.OnEnable();
  91. }
  92. /// <summary>
  93. /// Unity calls this method when the object goes out of scope.
  94. /// </summary>
  95. protected virtual void OnDisable()
  96. {
  97. if (parameters == null)
  98. return;
  99. foreach (var parameter in parameters)
  100. parameter.OnDisable();
  101. }
  102. /// <summary>
  103. /// Interpolates a <see cref="VolumeComponent"/> with this component by an interpolation
  104. /// factor and puts the result back into the given <see cref="VolumeComponent"/>.
  105. /// </summary>
  106. /// <remarks>
  107. /// You can override this method to do your own blending. Either loop through the
  108. /// <see cref="parameters"/> list or reference direct fields. You should only use
  109. /// <see cref="VolumeParameter.SetValue"/> to set parameter values and not assign
  110. /// directly to the state object. you should also manually check
  111. /// <see cref="VolumeParameter.overrideState"/> before you set any values.
  112. /// </remarks>
  113. /// <param name="state">The internal component to interpolate from. You must store
  114. /// the result of the interpolation in this same component.</param>
  115. /// <param name="interpFactor">The interpolation factor in range [0,1].</param>
  116. /// <example>
  117. /// Below is the default implementation for blending:
  118. /// <code>
  119. /// public virtual void Override(VolumeComponent state, float interpFactor)
  120. /// {
  121. /// int count = parameters.Count;
  122. ///
  123. /// for (int i = 0; i &lt; count; i++)
  124. /// {
  125. /// var stateParam = state.parameters[i];
  126. /// var toParam = parameters[i];
  127. ///
  128. /// // Keep track of the override state for debugging purpose
  129. /// stateParam.overrideState = toParam.overrideState;
  130. ///
  131. /// if (toParam.overrideState)
  132. /// stateParam.Interp(stateParam, toParam, interpFactor);
  133. /// }
  134. /// }
  135. /// </code>
  136. /// </example>
  137. public virtual void Override(VolumeComponent state, float interpFactor)
  138. {
  139. int count = parameters.Count;
  140. for (int i = 0; i < count; i++)
  141. {
  142. var stateParam = state.parameters[i];
  143. var toParam = parameters[i];
  144. // Keep track of the override state for debugging purpose
  145. stateParam.overrideState = toParam.overrideState;
  146. if (toParam.overrideState)
  147. stateParam.Interp(stateParam, toParam, interpFactor);
  148. }
  149. }
  150. /// <summary>
  151. /// Sets the state of all the overrides on this component to a given value.
  152. /// </summary>
  153. /// <param name="state">The value to set the state of the overrides to.</param>
  154. public void SetAllOverridesTo(bool state)
  155. {
  156. SetAllOverridesTo(parameters, state);
  157. }
  158. void SetAllOverridesTo(IEnumerable<VolumeParameter> enumerable, bool state)
  159. {
  160. foreach (var prop in enumerable)
  161. {
  162. prop.overrideState = state;
  163. var t = prop.GetType();
  164. if (VolumeParameter.IsObjectParameter(t))
  165. {
  166. // This method won't be called a lot but this is sub-optimal, fix me
  167. var innerParams = (ReadOnlyCollection<VolumeParameter>)
  168. t.GetProperty("parameters", BindingFlags.NonPublic | BindingFlags.Instance)
  169. .GetValue(prop, null);
  170. if (innerParams != null)
  171. SetAllOverridesTo(innerParams, state);
  172. }
  173. }
  174. }
  175. /// <summary>
  176. /// A custom hashing function that Unity uses to compare the state of parameters.
  177. /// </summary>
  178. /// <returns>A computed hash code for the current instance.</returns>
  179. public override int GetHashCode()
  180. {
  181. unchecked
  182. {
  183. //return parameters.Aggregate(17, (i, p) => i * 23 + p.GetHash());
  184. int hash = 17;
  185. for (int i = 0; i < parameters.Count; i++)
  186. hash = hash * 23 + parameters[i].GetHashCode();
  187. return hash;
  188. }
  189. }
  190. }
  191. }