暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ScriptableRendererDataEditor.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Text.RegularExpressions;
  5. using UnityEngine;
  6. using UnityEngine.Rendering;
  7. using UnityEngine.Rendering.Universal;
  8. using Object = UnityEngine.Object;
  9. namespace UnityEditor.Rendering.Universal
  10. {
  11. /// <summary>
  12. /// Editor script for a <c>ScriptableRendererData</c> class.
  13. /// </summary>
  14. [CustomEditor(typeof(ScriptableRendererData), true)]
  15. public class ScriptableRendererDataEditor : Editor
  16. {
  17. class Styles
  18. {
  19. public static readonly GUIContent RenderFeatures =
  20. new GUIContent("Renderer Features",
  21. "A Renderer Feature is an asset that lets you add extra Render passes to a URP Renderer and configure their behavior.");
  22. public static readonly GUIContent PassNameField =
  23. new GUIContent("Name", "Render pass name. This name is the name displayed in Frame Debugger.");
  24. public static readonly GUIContent MissingFeature = new GUIContent("Missing RendererFeature",
  25. "Missing reference, due to compilation issues or missing files. you can attempt auto fix or choose to remove the feature.");
  26. public static GUIStyle BoldLabelSimple;
  27. static Styles()
  28. {
  29. BoldLabelSimple = new GUIStyle(EditorStyles.label);
  30. BoldLabelSimple.fontStyle = FontStyle.Bold;
  31. }
  32. }
  33. private SerializedProperty m_RendererFeatures;
  34. private SerializedProperty m_RendererFeaturesMap;
  35. private SerializedProperty m_FalseBool;
  36. [SerializeField] private bool falseBool = false;
  37. List<Editor> m_Editors = new List<Editor>();
  38. private void OnEnable()
  39. {
  40. m_RendererFeatures = serializedObject.FindProperty(nameof(ScriptableRendererData.m_RendererFeatures));
  41. m_RendererFeaturesMap = serializedObject.FindProperty(nameof(ScriptableRendererData.m_RendererFeatureMap));
  42. var editorObj = new SerializedObject(this);
  43. m_FalseBool = editorObj.FindProperty(nameof(falseBool));
  44. UpdateEditorList();
  45. }
  46. private void OnDisable()
  47. {
  48. ClearEditorsList();
  49. }
  50. /// <inheritdoc/>
  51. public override void OnInspectorGUI()
  52. {
  53. if (m_RendererFeatures == null)
  54. OnEnable();
  55. else if (m_RendererFeatures.arraySize != m_Editors.Count)
  56. UpdateEditorList();
  57. serializedObject.Update();
  58. DrawRendererFeatureList();
  59. }
  60. private void DrawRendererFeatureList()
  61. {
  62. EditorGUILayout.LabelField(Styles.RenderFeatures, EditorStyles.boldLabel);
  63. EditorGUILayout.Space();
  64. if (m_RendererFeatures.arraySize == 0)
  65. {
  66. EditorGUILayout.HelpBox("No Renderer Features added", MessageType.Info);
  67. }
  68. else
  69. {
  70. //Draw List
  71. CoreEditorUtils.DrawSplitter();
  72. for (int i = 0; i < m_RendererFeatures.arraySize; i++)
  73. {
  74. SerializedProperty renderFeaturesProperty = m_RendererFeatures.GetArrayElementAtIndex(i);
  75. DrawRendererFeature(i, ref renderFeaturesProperty);
  76. CoreEditorUtils.DrawSplitter();
  77. }
  78. }
  79. EditorGUILayout.Space();
  80. //Add renderer
  81. using (var hscope = new EditorGUILayout.HorizontalScope())
  82. {
  83. if (GUILayout.Button("Add Renderer Feature", EditorStyles.miniButton))
  84. {
  85. var r = hscope.rect;
  86. var pos = new Vector2(r.x + r.width / 2f, r.yMax + 18f);
  87. FilterWindow.Show(pos, new ScriptableRendererFeatureProvider(this));
  88. }
  89. }
  90. }
  91. internal bool GetCustomTitle(Type type, out string title)
  92. {
  93. var isSingleFeature = type.GetCustomAttribute<DisallowMultipleRendererFeature>();
  94. if (isSingleFeature != null)
  95. {
  96. title = isSingleFeature.customTitle;
  97. return title != null;
  98. }
  99. title = null;
  100. return false;
  101. }
  102. private bool GetTooltip(Type type, out string tooltip)
  103. {
  104. var attribute = type.GetCustomAttribute<TooltipAttribute>();
  105. if (attribute != null)
  106. {
  107. tooltip = attribute.tooltip;
  108. return true;
  109. }
  110. tooltip = string.Empty;
  111. return false;
  112. }
  113. private void DrawRendererFeature(int index, ref SerializedProperty renderFeatureProperty)
  114. {
  115. Object rendererFeatureObjRef = renderFeatureProperty.objectReferenceValue;
  116. if (rendererFeatureObjRef != null)
  117. {
  118. bool hasChangedProperties = false;
  119. string title;
  120. bool hasCustomTitle = GetCustomTitle(rendererFeatureObjRef.GetType(), out title);
  121. if (!hasCustomTitle)
  122. {
  123. title = ObjectNames.GetInspectorTitle(rendererFeatureObjRef);
  124. }
  125. string tooltip;
  126. GetTooltip(rendererFeatureObjRef.GetType(), out tooltip);
  127. string helpURL;
  128. DocumentationUtils.TryGetHelpURL(rendererFeatureObjRef.GetType(), out helpURL);
  129. // Get the serialized object for the editor script & update it
  130. Editor rendererFeatureEditor = m_Editors[index];
  131. SerializedObject serializedRendererFeaturesEditor = rendererFeatureEditor.serializedObject;
  132. serializedRendererFeaturesEditor.Update();
  133. // Foldout header
  134. EditorGUI.BeginChangeCheck();
  135. SerializedProperty activeProperty = serializedRendererFeaturesEditor.FindProperty("m_Active");
  136. bool displayContent = CoreEditorUtils.DrawHeaderToggle(EditorGUIUtility.TrTextContent(title, tooltip), renderFeatureProperty, activeProperty, pos => OnContextClick(rendererFeatureObjRef, pos, index), null, null, helpURL);
  137. hasChangedProperties |= EditorGUI.EndChangeCheck();
  138. // ObjectEditor
  139. if (displayContent)
  140. {
  141. if (!hasCustomTitle)
  142. {
  143. EditorGUI.BeginChangeCheck();
  144. SerializedProperty nameProperty = serializedRendererFeaturesEditor.FindProperty("m_Name");
  145. nameProperty.stringValue = ValidateName(EditorGUILayout.DelayedTextField(Styles.PassNameField, nameProperty.stringValue));
  146. if (EditorGUI.EndChangeCheck())
  147. {
  148. hasChangedProperties = true;
  149. // We need to update sub-asset name
  150. rendererFeatureObjRef.name = nameProperty.stringValue;
  151. AssetDatabase.SaveAssets();
  152. // Triggers update for sub-asset name change
  153. ProjectWindowUtil.ShowCreatedAsset(target);
  154. }
  155. }
  156. EditorGUI.BeginChangeCheck();
  157. rendererFeatureEditor.OnInspectorGUI();
  158. hasChangedProperties |= EditorGUI.EndChangeCheck();
  159. EditorGUILayout.Space(EditorGUIUtility.singleLineHeight);
  160. }
  161. // Apply changes and save if the user has modified any settings
  162. if (hasChangedProperties)
  163. {
  164. serializedRendererFeaturesEditor.ApplyModifiedProperties();
  165. serializedObject.ApplyModifiedProperties();
  166. ForceSave();
  167. }
  168. }
  169. else
  170. {
  171. CoreEditorUtils.DrawHeaderToggle(Styles.MissingFeature, renderFeatureProperty, m_FalseBool, pos => OnContextClick(rendererFeatureObjRef, pos, index));
  172. m_FalseBool.boolValue = false; // always make sure false bool is false
  173. EditorGUILayout.HelpBox(Styles.MissingFeature.tooltip, MessageType.Error);
  174. if (GUILayout.Button("Attempt Fix", EditorStyles.miniButton))
  175. {
  176. ScriptableRendererData data = target as ScriptableRendererData;
  177. data.ValidateRendererFeatures();
  178. }
  179. }
  180. }
  181. private void OnContextClick(Object rendererFeatureObject, Vector2 position, int id)
  182. {
  183. var menu = new GenericMenu();
  184. if (id == 0)
  185. menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Move Up"));
  186. else
  187. menu.AddItem(EditorGUIUtility.TrTextContent("Move Up"), false, () => MoveComponent(id, -1));
  188. if (id == m_RendererFeatures.arraySize - 1)
  189. menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Move Down"));
  190. else
  191. menu.AddItem(EditorGUIUtility.TrTextContent("Move Down"), false, () => MoveComponent(id, 1));
  192. if(rendererFeatureObject?.GetType() == typeof(FullScreenPassRendererFeature))
  193. menu.AddAdvancedPropertiesBoolMenuItem();
  194. menu.AddSeparator(string.Empty);
  195. menu.AddItem(EditorGUIUtility.TrTextContent("Remove"), false, () => RemoveComponent(id));
  196. menu.DropDown(new Rect(position, Vector2.zero));
  197. }
  198. internal void AddComponent(Type type)
  199. {
  200. serializedObject.Update();
  201. ScriptableObject component = CreateInstance(type);
  202. component.name = $"{type.Name}";
  203. Undo.RegisterCreatedObjectUndo(component, "Add Renderer Feature");
  204. // Store this new effect as a sub-asset so we can reference it safely afterwards
  205. // Only when we're not dealing with an instantiated asset
  206. if (EditorUtility.IsPersistent(target))
  207. {
  208. AssetDatabase.AddObjectToAsset(component, target);
  209. }
  210. AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out var guid, out long localId);
  211. // Grow the list first, then add - that's how serialized lists work in Unity
  212. m_RendererFeatures.arraySize++;
  213. SerializedProperty componentProp = m_RendererFeatures.GetArrayElementAtIndex(m_RendererFeatures.arraySize - 1);
  214. componentProp.objectReferenceValue = component;
  215. // Update GUID Map
  216. m_RendererFeaturesMap.arraySize++;
  217. SerializedProperty guidProp = m_RendererFeaturesMap.GetArrayElementAtIndex(m_RendererFeaturesMap.arraySize - 1);
  218. guidProp.longValue = localId;
  219. UpdateEditorList();
  220. serializedObject.ApplyModifiedProperties();
  221. // Force save / refresh
  222. if (EditorUtility.IsPersistent(target))
  223. {
  224. ForceSave();
  225. }
  226. serializedObject.ApplyModifiedProperties();
  227. }
  228. private void RemoveComponent(int id)
  229. {
  230. SerializedProperty property = m_RendererFeatures.GetArrayElementAtIndex(id);
  231. Object component = property.objectReferenceValue;
  232. property.objectReferenceValue = null;
  233. Undo.SetCurrentGroupName(component == null ? "Remove Renderer Feature" : $"Remove {component.name}");
  234. // remove the array index itself from the list
  235. m_RendererFeatures.DeleteArrayElementAtIndex(id);
  236. m_RendererFeaturesMap.DeleteArrayElementAtIndex(id);
  237. UpdateEditorList();
  238. serializedObject.ApplyModifiedProperties();
  239. // Destroy the setting object after ApplyModifiedProperties(). If we do it before, redo
  240. // actions will be in the wrong order and the reference to the setting object in the
  241. // list will be lost.
  242. if (component != null)
  243. {
  244. Undo.DestroyObjectImmediate(component);
  245. ScriptableRendererFeature feature = component as ScriptableRendererFeature;
  246. feature?.Dispose();
  247. }
  248. // Force save / refresh
  249. ForceSave();
  250. }
  251. private void MoveComponent(int id, int offset)
  252. {
  253. Undo.SetCurrentGroupName("Move Render Feature");
  254. serializedObject.Update();
  255. m_RendererFeatures.MoveArrayElement(id, id + offset);
  256. m_RendererFeaturesMap.MoveArrayElement(id, id + offset);
  257. UpdateEditorList();
  258. serializedObject.ApplyModifiedProperties();
  259. // Force save / refresh
  260. ForceSave();
  261. }
  262. private string ValidateName(string name)
  263. {
  264. name = Regex.Replace(name, @"[^a-zA-Z0-9 ]", "");
  265. return name;
  266. }
  267. private void UpdateEditorList()
  268. {
  269. ClearEditorsList();
  270. for (int i = 0; i < m_RendererFeatures.arraySize; i++)
  271. {
  272. m_Editors.Add(CreateEditor(m_RendererFeatures.GetArrayElementAtIndex(i).objectReferenceValue));
  273. }
  274. }
  275. //To avoid leaking memory we destroy editors when we clear editors list
  276. private void ClearEditorsList()
  277. {
  278. for (int i = m_Editors.Count - 1; i >= 0; --i)
  279. {
  280. DestroyImmediate(m_Editors[i]);
  281. }
  282. m_Editors.Clear();
  283. }
  284. private void ForceSave()
  285. {
  286. EditorUtility.SetDirty(target);
  287. }
  288. }
  289. }