CinemachineVolumeSettingsEditor.cs 9.9 KB

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