ScriptableRendererData.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. #if UNITY_EDITOR
  5. using System.Linq;
  6. using UnityEditor;
  7. #endif
  8. namespace UnityEngine.Rendering.Universal
  9. {
  10. /// <summary>
  11. /// Class <c>ScriptableRendererData</c> contains resources for a <c>ScriptableRenderer</c>.
  12. /// <seealso cref="ScriptableRenderer"/>
  13. /// </summary>
  14. public abstract class ScriptableRendererData : ScriptableObject
  15. {
  16. internal bool isInvalidated { get; set; }
  17. /// <summary>
  18. /// Class contains references to shader resources used by Rendering Debugger.
  19. /// </summary>
  20. [Serializable, ReloadGroup]
  21. public sealed class DebugShaderResources
  22. {
  23. /// <summary>
  24. /// Debug shader used to output interpolated vertex attributes.
  25. /// </summary>
  26. [Reload("Shaders/Debug/DebugReplacement.shader")]
  27. public Shader debugReplacementPS;
  28. }
  29. /// <summary>
  30. /// Container for shader resources used by Rendering Debugger.
  31. /// </summary>
  32. public DebugShaderResources debugShaders;
  33. /// <summary>
  34. /// Creates the instance of the ScriptableRenderer.
  35. /// </summary>
  36. /// <returns>The instance of ScriptableRenderer</returns>
  37. protected abstract ScriptableRenderer Create();
  38. [SerializeField] internal List<ScriptableRendererFeature> m_RendererFeatures = new List<ScriptableRendererFeature>(10);
  39. [SerializeField] internal List<long> m_RendererFeatureMap = new List<long>(10);
  40. [SerializeField] bool m_UseNativeRenderPass = false;
  41. /// <summary>
  42. /// List of additional render pass features for this renderer.
  43. /// </summary>
  44. public List<ScriptableRendererFeature> rendererFeatures
  45. {
  46. get => m_RendererFeatures;
  47. }
  48. /// <summary>
  49. /// Use SetDirty when changing seeings in the ScriptableRendererData.
  50. /// It will rebuild the render passes with the new data.
  51. /// </summary>
  52. public new void SetDirty()
  53. {
  54. isInvalidated = true;
  55. }
  56. internal ScriptableRenderer InternalCreateRenderer()
  57. {
  58. isInvalidated = false;
  59. return Create();
  60. }
  61. protected virtual void OnValidate()
  62. {
  63. SetDirty();
  64. #if UNITY_EDITOR
  65. if (m_RendererFeatures.Contains(null))
  66. ValidateRendererFeatures();
  67. #endif
  68. }
  69. protected virtual void OnEnable()
  70. {
  71. SetDirty();
  72. }
  73. public bool useNativeRenderPass
  74. {
  75. get => m_UseNativeRenderPass;
  76. set
  77. {
  78. SetDirty();
  79. m_UseNativeRenderPass = value;
  80. }
  81. }
  82. /// <summary>
  83. /// Returns true if contains renderer feature with specified type.
  84. /// </summary>
  85. /// <typeparam name="T">Renderer Feature type.</typeparam>
  86. /// <returns></returns>
  87. internal bool TryGetRendererFeature<T>(out T rendererFeature) where T : ScriptableRendererFeature
  88. {
  89. foreach (var target in rendererFeatures)
  90. {
  91. if (target.GetType() == typeof(T))
  92. {
  93. rendererFeature = target as T;
  94. return true;
  95. }
  96. }
  97. rendererFeature = null;
  98. return false;
  99. }
  100. #if UNITY_EDITOR
  101. internal virtual Material GetDefaultMaterial(DefaultMaterialType materialType)
  102. {
  103. return null;
  104. }
  105. internal virtual Shader GetDefaultShader()
  106. {
  107. return null;
  108. }
  109. internal bool ValidateRendererFeatures()
  110. {
  111. // Get all Subassets
  112. var subassets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(this));
  113. var linkedIds = new List<long>();
  114. var loadedAssets = new Dictionary<long, object>();
  115. var mapValid = m_RendererFeatureMap != null && m_RendererFeatureMap?.Count == m_RendererFeatures?.Count;
  116. var debugOutput = $"{name}\nValid Sub-assets:\n";
  117. // Collect valid, compiled sub-assets
  118. foreach (var asset in subassets)
  119. {
  120. if (asset == null || asset.GetType().BaseType != typeof(ScriptableRendererFeature)) continue;
  121. AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out var guid, out long localId);
  122. loadedAssets.Add(localId, asset);
  123. debugOutput += $"-{asset.name}\n--localId={localId}\n";
  124. }
  125. // Collect assets that are connected to the list
  126. for (var i = 0; i < m_RendererFeatures?.Count; i++)
  127. {
  128. if (!m_RendererFeatures[i]) continue;
  129. if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(m_RendererFeatures[i], out var guid, out long localId))
  130. {
  131. linkedIds.Add(localId);
  132. }
  133. }
  134. var mapDebug = mapValid ? "Linking" : "Map missing, will attempt to re-map";
  135. debugOutput += $"Feature List Status({mapDebug}):\n";
  136. // Try fix missing references
  137. for (var i = 0; i < m_RendererFeatures?.Count; i++)
  138. {
  139. if (m_RendererFeatures[i] == null)
  140. {
  141. if (mapValid && m_RendererFeatureMap[i] != 0)
  142. {
  143. var localId = m_RendererFeatureMap[i];
  144. loadedAssets.TryGetValue(localId, out var asset);
  145. m_RendererFeatures[i] = (ScriptableRendererFeature)asset;
  146. }
  147. else
  148. {
  149. m_RendererFeatures[i] = (ScriptableRendererFeature)GetUnusedAsset(ref linkedIds, ref loadedAssets);
  150. }
  151. }
  152. debugOutput += m_RendererFeatures[i] != null ? $"-{i}:Linked\n" : $"-{i}:Missing\n";
  153. }
  154. UpdateMap();
  155. if (!m_RendererFeatures.Contains(null))
  156. return true;
  157. Debug.LogError($"{name} is missing RendererFeatures\nThis could be due to missing scripts or compile error.", this);
  158. return false;
  159. }
  160. internal bool DuplicateFeatureCheck(Type type)
  161. {
  162. var isSingleFeature = type.GetCustomAttribute(typeof(DisallowMultipleRendererFeature));
  163. return isSingleFeature != null && m_RendererFeatures.Select(renderFeature => renderFeature.GetType()).Any(t => t == type);
  164. }
  165. private static object GetUnusedAsset(ref List<long> usedIds, ref Dictionary<long, object> assets)
  166. {
  167. foreach (var asset in assets)
  168. {
  169. var alreadyLinked = usedIds.Any(used => asset.Key == used);
  170. if (alreadyLinked)
  171. continue;
  172. usedIds.Add(asset.Key);
  173. return asset.Value;
  174. }
  175. return null;
  176. }
  177. private void UpdateMap()
  178. {
  179. if (m_RendererFeatureMap.Count != m_RendererFeatures.Count)
  180. {
  181. m_RendererFeatureMap.Clear();
  182. m_RendererFeatureMap.AddRange(new long[m_RendererFeatures.Count]);
  183. }
  184. for (int i = 0; i < rendererFeatures.Count; i++)
  185. {
  186. if (m_RendererFeatures[i] == null) continue;
  187. if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(m_RendererFeatures[i], out var guid, out long localId)) continue;
  188. m_RendererFeatureMap[i] = localId;
  189. }
  190. }
  191. #endif
  192. }
  193. }