CinemachinePostProcessingEditor.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #if CINEMACHINE_POST_PROCESSING_V2
  2. using UnityEngine;
  3. using UnityEditor;
  4. using UnityEngine.Rendering.PostProcessing;
  5. using UnityEditor.Rendering.PostProcessing;
  6. using System.Collections.Generic;
  7. #endif
  8. namespace Cinemachine.PostFX.Editor
  9. {
  10. #if CINEMACHINE_POST_PROCESSING_V2
  11. [CustomEditor(typeof(CinemachinePostProcessing))]
  12. public sealed class CinemachinePostProcessingEditor
  13. : Cinemachine.Editor.BaseEditor<CinemachinePostProcessing>
  14. {
  15. SerializedProperty m_Profile;
  16. SerializedProperty m_FocusTracking;
  17. EffectListEditor m_EffectList;
  18. GUIContent m_ProfileLabel;
  19. void OnEnable()
  20. {
  21. Texture texture = AssetDatabase.LoadAssetAtPath<Texture>(
  22. Cinemachine.Editor.ScriptableObjectUtility.CinemachineRealativeInstallPath
  23. + "/Editor/EditorResources/PostProcessLayer.png");
  24. m_ProfileLabel = new GUIContent("Profile", texture, "A reference to a profile asset");
  25. m_FocusTracking = FindProperty(x => x.m_FocusTracking);
  26. m_Profile = FindProperty(x => x.m_Profile);
  27. m_EffectList = new EffectListEditor(this);
  28. RefreshEffectListEditor(Target.m_Profile);
  29. }
  30. void OnDisable()
  31. {
  32. if (m_EffectList != null)
  33. m_EffectList.Clear();
  34. }
  35. void RefreshEffectListEditor(PostProcessProfile asset)
  36. {
  37. if (m_EffectList == null)
  38. m_EffectList = new EffectListEditor(this);
  39. m_EffectList.Clear();
  40. if (asset != null)
  41. m_EffectList.Init(asset, new SerializedObject(asset));
  42. }
  43. /// <summary>Get the property names to exclude in the inspector.</summary>
  44. /// <param name="excluded">Add the names to this list</param>
  45. protected override void GetExcludedPropertiesInInspector(List<string> excluded)
  46. {
  47. base.GetExcludedPropertiesInInspector(excluded);
  48. var mode = (CinemachinePostProcessing.FocusTrackingMode)m_FocusTracking.intValue;
  49. if (mode != CinemachinePostProcessing.FocusTrackingMode.CustomTarget)
  50. excluded.Add(FieldPath(x => x.m_FocusTarget));
  51. if (mode == CinemachinePostProcessing.FocusTrackingMode.None)
  52. excluded.Add(FieldPath(x => x.m_FocusOffset));
  53. excluded.Add(FieldPath(x => x.m_Profile));
  54. }
  55. public override void OnInspectorGUI()
  56. {
  57. BeginInspector();
  58. DrawRemainingPropertiesInInspector();
  59. var focusMode = (CinemachinePostProcessing.FocusTrackingMode)m_FocusTracking.intValue;
  60. if (focusMode != CinemachinePostProcessing.FocusTrackingMode.None)
  61. {
  62. bool valid = false;
  63. DepthOfField dof;
  64. if (Target.m_Profile != null && Target.m_Profile.TryGetSettings(out dof))
  65. valid = dof.enabled && dof.active && dof.focusDistance.overrideState;
  66. if (!valid)
  67. EditorGUILayout.HelpBox(
  68. "Focus Tracking requires an active DepthOfField/FocusDistance effect in the profile",
  69. MessageType.Warning);
  70. }
  71. EditorGUI.BeginChangeCheck();
  72. DrawProfileInspectorGUI();
  73. if (EditorGUI.EndChangeCheck())
  74. {
  75. Target.InvalidateCachedProfile();
  76. serializedObject.ApplyModifiedProperties();
  77. }
  78. }
  79. void DrawProfileInspectorGUI()
  80. {
  81. EditorGUILayout.Space();
  82. bool assetHasChanged = false;
  83. bool showCopy = m_Profile.objectReferenceValue != null;
  84. // The layout system sort of break alignement when mixing inspector fields with custom
  85. // layouted fields, do the layout manually instead
  86. int buttonWidth = showCopy ? 45 : 60;
  87. float indentOffset = EditorGUI.indentLevel * 15f;
  88. var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
  89. var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height);
  90. var fieldRect = new Rect(labelRect.xMax, lineRect.y, lineRect.width - labelRect.width - buttonWidth * (showCopy ? 2 : 1), lineRect.height);
  91. var buttonNewRect = new Rect(fieldRect.xMax, lineRect.y, buttonWidth, lineRect.height);
  92. var buttonCopyRect = new Rect(buttonNewRect.xMax, lineRect.y, buttonWidth, lineRect.height);
  93. EditorGUI.PrefixLabel(labelRect, m_ProfileLabel);
  94. using (var scope = new EditorGUI.ChangeCheckScope())
  95. {
  96. m_Profile.objectReferenceValue
  97. = (PostProcessProfile)EditorGUI.ObjectField(
  98. fieldRect, m_Profile.objectReferenceValue, typeof(PostProcessProfile), false);
  99. assetHasChanged = scope.changed;
  100. }
  101. if (GUI.Button(
  102. buttonNewRect,
  103. EditorUtilities.GetContent("New|Create a new profile."),
  104. showCopy ? EditorStyles.miniButtonLeft : EditorStyles.miniButton))
  105. {
  106. // By default, try to put assets in a folder next to the currently active
  107. // scene file. If the user isn't a scene, put them in root instead.
  108. var targetName = Target.name;
  109. var scene = Target.gameObject.scene;
  110. var asset = CreatePostProcessProfile(scene, targetName);
  111. m_Profile.objectReferenceValue = asset;
  112. assetHasChanged = true;
  113. }
  114. if (showCopy && GUI.Button(
  115. buttonCopyRect,
  116. EditorUtilities.GetContent("Clone|Create a new profile and copy the content of the currently assigned profile."),
  117. EditorStyles.miniButtonRight))
  118. {
  119. // Duplicate the currently assigned profile and save it as a new profile
  120. var origin = (PostProcessProfile)m_Profile.objectReferenceValue;
  121. var path = AssetDatabase.GetAssetPath(origin);
  122. path = AssetDatabase.GenerateUniqueAssetPath(path);
  123. var asset = Instantiate(origin);
  124. asset.settings.Clear();
  125. AssetDatabase.CreateAsset(asset, path);
  126. foreach (var item in origin.settings)
  127. {
  128. var itemCopy = Instantiate(item);
  129. itemCopy.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
  130. itemCopy.name = item.name;
  131. asset.settings.Add(itemCopy);
  132. AssetDatabase.AddObjectToAsset(itemCopy, asset);
  133. }
  134. AssetDatabase.SaveAssets();
  135. AssetDatabase.Refresh();
  136. m_Profile.objectReferenceValue = asset;
  137. assetHasChanged = true;
  138. }
  139. if (m_Profile.objectReferenceValue == null)
  140. {
  141. if (assetHasChanged && m_EffectList != null)
  142. m_EffectList.Clear(); // Asset wasn't null before, do some cleanup
  143. EditorGUILayout.HelpBox(
  144. "Assign an existing Post-process Profile by choosing an asset, or create a new one by "
  145. + "clicking the \"New\" button.\nNew assets are automatically put in a folder next "
  146. + "to your scene file. If your scene hasn't been saved yet they will be created "
  147. + "at the root of the Assets folder.",
  148. MessageType.Info);
  149. }
  150. else
  151. {
  152. if (assetHasChanged)
  153. RefreshEffectListEditor((PostProcessProfile)m_Profile.objectReferenceValue);
  154. if (m_EffectList != null)
  155. m_EffectList.OnGUI();
  156. }
  157. }
  158. // Copied from UnityEditor.Rendering.PostProcessing.ProfileFactory.CreatePostProcessProfile() because it's internal
  159. static PostProcessProfile CreatePostProcessProfile(UnityEngine.SceneManagement.Scene scene, string targetName)
  160. {
  161. var path = string.Empty;
  162. if (string.IsNullOrEmpty(scene.path))
  163. {
  164. path = "Assets/";
  165. }
  166. else
  167. {
  168. var scenePath = System.IO.Path.GetDirectoryName(scene.path);
  169. var extPath = scene.name + "_Profiles";
  170. var profilePath = scenePath + "/" + extPath;
  171. if (!AssetDatabase.IsValidFolder(profilePath))
  172. AssetDatabase.CreateFolder(scenePath, extPath);
  173. path = profilePath + "/";
  174. }
  175. path += targetName + " Profile.asset";
  176. path = AssetDatabase.GenerateUniqueAssetPath(path);
  177. var profile = ScriptableObject.CreateInstance<PostProcessProfile>();
  178. AssetDatabase.CreateAsset(profile, path);
  179. AssetDatabase.SaveAssets();
  180. AssetDatabase.Refresh();
  181. return profile;
  182. }
  183. }
  184. #endif
  185. }