PostProcessVolumeEditor.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using UnityEngine;
  2. using UnityEngine.Rendering.PostProcessing;
  3. namespace UnityEditor.Rendering.PostProcessing
  4. {
  5. [CanEditMultipleObjects, CustomEditor(typeof(PostProcessVolume))]
  6. sealed class PostProcessVolumeEditor : BaseEditor<PostProcessVolume>
  7. {
  8. SerializedProperty m_Profile;
  9. SerializedProperty m_IsGlobal;
  10. SerializedProperty m_BlendRadius;
  11. SerializedProperty m_Weight;
  12. SerializedProperty m_Priority;
  13. EffectListEditor m_EffectList;
  14. void OnEnable()
  15. {
  16. m_Profile = FindProperty(x => x.sharedProfile);
  17. m_IsGlobal = FindProperty(x => x.isGlobal);
  18. m_BlendRadius = FindProperty(x => x.blendDistance);
  19. m_Weight = FindProperty(x => x.weight);
  20. m_Priority = FindProperty(x => x.priority);
  21. m_EffectList = new EffectListEditor(this);
  22. RefreshEffectListEditor(m_Target.sharedProfile);
  23. }
  24. void OnDisable()
  25. {
  26. if (m_EffectList != null)
  27. m_EffectList.Clear();
  28. }
  29. void RefreshEffectListEditor(PostProcessProfile asset)
  30. {
  31. m_EffectList.Clear();
  32. if (asset != null)
  33. m_EffectList.Init(asset, new SerializedObject(asset));
  34. }
  35. public override void OnInspectorGUI()
  36. {
  37. serializedObject.Update();
  38. EditorGUILayout.PropertyField(m_IsGlobal);
  39. if (!m_IsGlobal.boolValue) // Blend radius is not needed for global volumes
  40. EditorGUILayout.PropertyField(m_BlendRadius);
  41. EditorGUILayout.PropertyField(m_Weight);
  42. EditorGUILayout.PropertyField(m_Priority);
  43. bool assetHasChanged = false;
  44. bool showCopy = m_Profile.objectReferenceValue != null;
  45. bool multiEdit = m_Profile.hasMultipleDifferentValues;
  46. // The layout system sort of break alignement when mixing inspector fields with custom
  47. // layouted fields, do the layout manually instead
  48. int buttonWidth = showCopy ? 45 : 60;
  49. float indentOffset = EditorGUI.indentLevel * 15f;
  50. var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
  51. var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height);
  52. var fieldRect = new Rect(labelRect.xMax, lineRect.y, lineRect.width - labelRect.width - buttonWidth * (showCopy ? 2 : 1), lineRect.height);
  53. var buttonNewRect = new Rect(fieldRect.xMax, lineRect.y, buttonWidth, lineRect.height);
  54. var buttonCopyRect = new Rect(buttonNewRect.xMax, lineRect.y, buttonWidth, lineRect.height);
  55. EditorGUI.PrefixLabel(labelRect, EditorUtilities.GetContent(m_Target.HasInstantiatedProfile() ? "Profile (Instance)|A copy of a profile asset." : "Profile|A reference to a profile asset."));
  56. using (var scope = new EditorGUI.ChangeCheckScope())
  57. {
  58. EditorGUI.BeginProperty(fieldRect, GUIContent.none, m_Profile);
  59. PostProcessProfile profile = null;
  60. if (m_Target.HasInstantiatedProfile())
  61. profile = (PostProcessProfile)EditorGUI.ObjectField(fieldRect, m_Target.profile, typeof(PostProcessProfile), false);
  62. else
  63. profile = (PostProcessProfile)EditorGUI.ObjectField(fieldRect, m_Profile.objectReferenceValue, typeof(PostProcessProfile), false);
  64. if (scope.changed)
  65. {
  66. assetHasChanged = true;
  67. m_Profile.objectReferenceValue = profile;
  68. if (m_Target.HasInstantiatedProfile()) // Clear the instantiated profile, from now on we're using shared again.
  69. m_Target.profile = null;
  70. }
  71. EditorGUI.EndProperty();
  72. }
  73. using (new EditorGUI.DisabledScope(multiEdit))
  74. {
  75. if (GUI.Button(buttonNewRect, EditorUtilities.GetContent("New|Create a new profile."), showCopy ? EditorStyles.miniButtonLeft : EditorStyles.miniButton))
  76. {
  77. // By default, try to put assets in a folder next to the currently active
  78. // scene file. If the user isn't a scene, put them in root instead.
  79. var targetName = m_Target.name;
  80. var scene = m_Target.gameObject.scene;
  81. var asset = ProfileFactory.CreatePostProcessProfile(scene, targetName);
  82. m_Profile.objectReferenceValue = asset;
  83. m_Target.profile = null; // Make sure we're not using an instantiated profile anymore
  84. assetHasChanged = true;
  85. }
  86. if (showCopy && GUI.Button(buttonCopyRect, EditorUtilities.GetContent(m_Target.HasInstantiatedProfile() ? "Save|Save the instantiated profile" : "Clone|Create a new profile and copy the content of the currently assigned profile."), EditorStyles.miniButtonRight))
  87. {
  88. // Duplicate the currently assigned profile and save it as a new profile
  89. var origin = profileRef;
  90. var path = AssetDatabase.GetAssetPath(m_Profile.objectReferenceValue);
  91. path = AssetDatabase.GenerateUniqueAssetPath(path);
  92. var asset = Instantiate(origin);
  93. asset.settings.Clear();
  94. AssetDatabase.CreateAsset(asset, path);
  95. foreach (var item in origin.settings)
  96. {
  97. var itemCopy = Instantiate(item);
  98. itemCopy.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
  99. itemCopy.name = item.name;
  100. asset.settings.Add(itemCopy);
  101. AssetDatabase.AddObjectToAsset(itemCopy, asset);
  102. }
  103. AssetDatabase.SaveAssets();
  104. AssetDatabase.Refresh();
  105. m_Profile.objectReferenceValue = asset;
  106. m_Target.profile = null; // Make sure we're not using an instantiated profile anymore
  107. assetHasChanged = true;
  108. }
  109. }
  110. EditorGUILayout.Space();
  111. if (m_Profile.objectReferenceValue == null && !m_Target.HasInstantiatedProfile())
  112. {
  113. if (assetHasChanged)
  114. m_EffectList.Clear(); // Asset wasn't null before, do some cleanup
  115. EditorGUILayout.HelpBox("Assign a Post-process Profile to this volume using the \"Asset\" field or create one automatically by clicking the \"New\" button.\nAssets are automatically put in a folder next to your scene file. If you scene hasn't been saved yet they will be created at the root of the Assets folder.", MessageType.Info);
  116. }
  117. else
  118. {
  119. if (assetHasChanged || profileRef != m_EffectList.asset) //Refresh when the user just dragged in a new asset, or when it was instantiated by code.
  120. RefreshEffectListEditor(profileRef);
  121. if (!multiEdit)
  122. m_EffectList.OnGUI();
  123. }
  124. serializedObject.ApplyModifiedProperties();
  125. }
  126. public PostProcessProfile profileRef
  127. {
  128. get { return m_Target.HasInstantiatedProfile() ? m_Target.profile : m_Target.sharedProfile; }
  129. }
  130. }
  131. }