CinemachineVolumeSettingsEditor.cs 9.8 KB

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