CinemachineShotEditor.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #if !UNITY_2019_1_OR_NEWER
  2. #define CINEMACHINE_TIMELINE
  3. #endif
  4. #if CINEMACHINE_TIMELINE
  5. using UnityEditor;
  6. using UnityEngine;
  7. using Cinemachine.Editor;
  8. using System.Collections.Generic;
  9. using UnityEditor.Timeline;
  10. using Cinemachine;
  11. //namespace Cinemachine.Timeline
  12. //{
  13. [CustomEditor(typeof(CinemachineShot))]
  14. internal sealed class CinemachineShotEditor : BaseEditor<CinemachineShot>
  15. {
  16. static string kAutoCreateKey = "CM_Timeline_AutoCreateShotFromSceneView";
  17. public static bool AutoCreateShotFromSceneView
  18. {
  19. get { return EditorPrefs.GetBool(kAutoCreateKey, false); }
  20. set
  21. {
  22. if (value != AutoCreateShotFromSceneView)
  23. EditorPrefs.SetBool(kAutoCreateKey, value);
  24. }
  25. }
  26. #if UNITY_2019_2_OR_NEWER
  27. static string kUseScrubbingCache = "CNMCN_Timeline_CachedScrubbing";
  28. public static bool UseScrubbingCache
  29. {
  30. get { return EditorPrefs.GetBool(kUseScrubbingCache, false); }
  31. set
  32. {
  33. if (UseScrubbingCache != value)
  34. {
  35. EditorPrefs.SetBool(kUseScrubbingCache, value);
  36. TargetPositionCache.UseCache = value;
  37. }
  38. }
  39. }
  40. [InitializeOnLoad]
  41. public class SyncCacheEnabledSetting
  42. {
  43. static SyncCacheEnabledSetting()
  44. {
  45. TargetPositionCache.UseCache = UseScrubbingCache;
  46. }
  47. }
  48. #endif
  49. static public CinemachineVirtualCameraBase CreateStaticVcamFromSceneView()
  50. {
  51. CinemachineVirtualCameraBase vcam = CinemachineMenu.CreateStaticVirtualCamera();
  52. vcam.m_StandbyUpdate = CinemachineVirtualCameraBase.StandbyUpdateMode.Never;
  53. #if false
  54. // GML this is too bold. What if timeline is a child of something moving?
  55. // also, SetActive(false) prevents the animator from being able to animate the object
  56. vcam.gameObject.SetActive(false);
  57. #if UNITY_2018_3_OR_NEWER
  58. var d = TimelineEditor.inspectedDirector;
  59. if (d != null)
  60. Undo.SetTransformParent(vcam.transform, d.transform, "");
  61. #endif
  62. #endif
  63. return vcam;
  64. }
  65. private static readonly GUIContent kVirtualCameraLabel
  66. = new GUIContent("Virtual Camera", "The virtual camera to use for this shot");
  67. private static readonly GUIContent kAutoCreateLabel = new GUIContent(
  68. "Auto-create new shots", "When enabled, new clips will be "
  69. + "automatically populated to match the scene view camera. "
  70. + "This is a global setting");
  71. #if UNITY_2019_2_OR_NEWER
  72. private static readonly GUIContent kScrubbingCacheLabel = new GUIContent(
  73. "Cached Scrubbing",
  74. "For preview scrubbing, caches target positions and pre-simulates each frame to "
  75. + "approximate damping and noise playback. Target position cache is built when timeline is "
  76. + "played forward, and used when timeline is scrubbed within the indicated zone. "
  77. + "This is a global setting,.");
  78. GUIContent m_ClearText = new GUIContent("Clear", "Clear the target position scrubbing cache");
  79. #endif
  80. /// <summary>Get the property names to exclude in the inspector.</summary>
  81. /// <param name="excluded">Add the names to this list</param>
  82. protected override void GetExcludedPropertiesInInspector(List<string> excluded)
  83. {
  84. base.GetExcludedPropertiesInInspector(excluded);
  85. excluded.Add(FieldPath(x => x.VirtualCamera));
  86. }
  87. private void OnDisable()
  88. {
  89. DestroyComponentEditors();
  90. }
  91. private void OnDestroy()
  92. {
  93. DestroyComponentEditors();
  94. }
  95. public override void OnInspectorGUI()
  96. {
  97. BeginInspector();
  98. SerializedProperty vcamProperty = FindProperty(x => x.VirtualCamera);
  99. EditorGUI.indentLevel = 0; // otherwise subeditor layouts get screwed up
  100. AutoCreateShotFromSceneView
  101. = EditorGUILayout.Toggle(kAutoCreateLabel, AutoCreateShotFromSceneView);
  102. Rect rect;
  103. #if UNITY_2019_2_OR_NEWER
  104. GUI.enabled = !Application.isPlaying;
  105. rect = EditorGUILayout.GetControlRect();
  106. var r = rect;
  107. r.width = EditorGUIUtility.labelWidth + EditorGUIUtility.singleLineHeight;
  108. if (Application.isPlaying)
  109. EditorGUI.Toggle(r, kScrubbingCacheLabel, false);
  110. else
  111. UseScrubbingCache = EditorGUI.Toggle(r, kScrubbingCacheLabel, UseScrubbingCache);
  112. r.x += r.width; r.width = rect.width - r.width;
  113. var buttonWidth = GUI.skin.button.CalcSize(m_ClearText).x;
  114. r.width -= buttonWidth;
  115. EditorGUI.LabelField(r, "(experimental)");
  116. r.x += r.width; r.width =buttonWidth;
  117. GUI.enabled &= !TargetPositionCache.IsEmpty;
  118. if (GUI.Button(r, m_ClearText))
  119. TargetPositionCache.ClearCache();
  120. GUI.enabled = true;
  121. #endif
  122. EditorGUILayout.Space();
  123. CinemachineVirtualCameraBase vcam
  124. = vcamProperty.exposedReferenceValue as CinemachineVirtualCameraBase;
  125. if (vcam != null)
  126. EditorGUILayout.PropertyField(vcamProperty, kVirtualCameraLabel);
  127. else
  128. {
  129. GUIContent createLabel = new GUIContent("Create");
  130. Vector2 createSize = GUI.skin.button.CalcSize(createLabel);
  131. rect = EditorGUILayout.GetControlRect(true);
  132. rect.width -= createSize.x;
  133. EditorGUI.PropertyField(rect, vcamProperty, kVirtualCameraLabel);
  134. rect.x += rect.width; rect.width = createSize.x;
  135. if (GUI.Button(rect, createLabel))
  136. {
  137. vcam = CreateStaticVcamFromSceneView();
  138. vcamProperty.exposedReferenceValue = vcam;
  139. }
  140. serializedObject.ApplyModifiedProperties();
  141. }
  142. EditorGUI.BeginChangeCheck();
  143. DrawRemainingPropertiesInInspector();
  144. if (vcam != null)
  145. DrawSubeditors(vcam);
  146. // by default timeline rebuilds the entire graph when something changes,
  147. // but if a property of the virtual camera changes, we only need to re-evaluate the timeline.
  148. // this prevents flicker on post processing updates
  149. if (EditorGUI.EndChangeCheck())
  150. {
  151. #if UNITY_2018_3_OR_NEWER
  152. TimelineEditor.Refresh(RefreshReason.SceneNeedsUpdate);
  153. #endif
  154. GUI.changed = false;
  155. }
  156. }
  157. void DrawSubeditors(CinemachineVirtualCameraBase vcam)
  158. {
  159. // Create an editor for each of the cinemachine virtual cam and its components
  160. GUIStyle foldoutStyle = new GUIStyle(EditorStyles.foldout) { fontStyle = FontStyle.Bold };
  161. UpdateComponentEditors(vcam);
  162. if (m_editors != null)
  163. {
  164. foreach (UnityEditor.Editor e in m_editors)
  165. {
  166. if (e == null || e.target == null || (e.target.hideFlags & HideFlags.HideInInspector) != 0)
  167. continue;
  168. // Separator line - how do you make a thinner one?
  169. GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(1) } );
  170. bool expanded = true;
  171. if (!s_EditorExpanded.TryGetValue(e.target.GetType(), out expanded))
  172. expanded = true;
  173. expanded = EditorGUILayout.Foldout(
  174. expanded, e.target.GetType().Name, true, foldoutStyle);
  175. if (expanded)
  176. e.OnInspectorGUI();
  177. s_EditorExpanded[e.target.GetType()] = expanded;
  178. }
  179. }
  180. }
  181. CinemachineVirtualCameraBase m_cachedReferenceObject;
  182. UnityEditor.Editor[] m_editors = null;
  183. static Dictionary<System.Type, bool> s_EditorExpanded = new Dictionary<System.Type, bool>();
  184. void UpdateComponentEditors(CinemachineVirtualCameraBase obj)
  185. {
  186. MonoBehaviour[] components = null;
  187. if (obj != null)
  188. components = obj.gameObject.GetComponents<MonoBehaviour>();
  189. int numComponents = (components == null) ? 0 : components.Length;
  190. int numEditors = (m_editors == null) ? 0 : m_editors.Length;
  191. if (m_cachedReferenceObject != obj || (numComponents + 1) != numEditors)
  192. {
  193. DestroyComponentEditors();
  194. m_cachedReferenceObject = obj;
  195. if (obj != null)
  196. {
  197. m_editors = new UnityEditor.Editor[components.Length + 1];
  198. CreateCachedEditor(obj.gameObject.GetComponent<Transform>(), null, ref m_editors[0]);
  199. for (int i = 0; i < components.Length; ++i)
  200. CreateCachedEditor(components[i], null, ref m_editors[i + 1]);
  201. }
  202. }
  203. }
  204. void DestroyComponentEditors()
  205. {
  206. m_cachedReferenceObject = null;
  207. if (m_editors != null)
  208. {
  209. for (int i = 0; i < m_editors.Length; ++i)
  210. {
  211. if (m_editors[i] != null)
  212. UnityEngine.Object.DestroyImmediate(m_editors[i]);
  213. m_editors[i] = null;
  214. }
  215. m_editors = null;
  216. }
  217. }
  218. }
  219. //}
  220. #endif