CinemachineShotEditor.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 CreatePassiveVcamFromSceneView()
  50. {
  51. var vcam = CinemachineMenu.CreatePassiveVirtualCamera("Virtual Camera", null, false);
  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. var d = TimelineEditor.inspectedDirector;
  58. if (d != null)
  59. Undo.SetTransformParent(vcam.transform, d.transform, "");
  60. #endif
  61. return vcam;
  62. }
  63. private static readonly GUIContent kVirtualCameraLabel
  64. = new GUIContent("Virtual Camera", "The virtual camera to use for this shot");
  65. private static readonly GUIContent kAutoCreateLabel = new GUIContent(
  66. "Auto-create new shots", "When enabled, new clips will be "
  67. + "automatically populated to match the scene view camera. "
  68. + "This is a global setting");
  69. #if UNITY_2019_2_OR_NEWER
  70. private static readonly GUIContent kScrubbingCacheLabel = new GUIContent(
  71. "Cached Scrubbing",
  72. "For preview scrubbing, caches target positions and pre-simulates each frame to "
  73. + "approximate damping and noise playback. Target position cache is built when timeline is "
  74. + "played forward, and used when timeline is scrubbed within the indicated zone. "
  75. + "This is a global setting,.");
  76. GUIContent m_ClearText = new GUIContent("Clear", "Clear the target position scrubbing cache");
  77. #endif
  78. /// <summary>Get the property names to exclude in the inspector.</summary>
  79. /// <param name="excluded">Add the names to this list</param>
  80. protected override void GetExcludedPropertiesInInspector(List<string> excluded)
  81. {
  82. base.GetExcludedPropertiesInInspector(excluded);
  83. excluded.Add(FieldPath(x => x.VirtualCamera));
  84. }
  85. private void OnDisable()
  86. {
  87. DestroyComponentEditors();
  88. }
  89. private void OnDestroy()
  90. {
  91. DestroyComponentEditors();
  92. }
  93. public override void OnInspectorGUI()
  94. {
  95. BeginInspector();
  96. SerializedProperty vcamProperty = FindProperty(x => x.VirtualCamera);
  97. EditorGUI.indentLevel = 0; // otherwise subeditor layouts get screwed up
  98. AutoCreateShotFromSceneView
  99. = EditorGUILayout.Toggle(kAutoCreateLabel, AutoCreateShotFromSceneView);
  100. Rect rect;
  101. #if UNITY_2019_2_OR_NEWER
  102. GUI.enabled = !Application.isPlaying;
  103. rect = EditorGUILayout.GetControlRect();
  104. var r = rect;
  105. r.width = EditorGUIUtility.labelWidth + EditorGUIUtility.singleLineHeight;
  106. if (Application.isPlaying)
  107. EditorGUI.Toggle(r, kScrubbingCacheLabel, false);
  108. else
  109. UseScrubbingCache = EditorGUI.Toggle(r, kScrubbingCacheLabel, UseScrubbingCache);
  110. r.x += r.width; r.width = rect.width - r.width;
  111. var buttonWidth = GUI.skin.button.CalcSize(m_ClearText).x;
  112. r.width -= buttonWidth;
  113. EditorGUI.LabelField(r, "(experimental)");
  114. r.x += r.width; r.width =buttonWidth;
  115. GUI.enabled &= !TargetPositionCache.IsEmpty;
  116. if (GUI.Button(r, m_ClearText))
  117. TargetPositionCache.ClearCache();
  118. GUI.enabled = true;
  119. #endif
  120. EditorGUILayout.Space();
  121. CinemachineVirtualCameraBase vcam
  122. = vcamProperty.exposedReferenceValue as CinemachineVirtualCameraBase;
  123. if (vcam != null)
  124. EditorGUILayout.PropertyField(vcamProperty, kVirtualCameraLabel);
  125. else
  126. {
  127. GUIContent createLabel = new GUIContent("Create");
  128. Vector2 createSize = GUI.skin.button.CalcSize(createLabel);
  129. rect = EditorGUILayout.GetControlRect(true);
  130. rect.width -= createSize.x;
  131. EditorGUI.PropertyField(rect, vcamProperty, kVirtualCameraLabel);
  132. rect.x += rect.width; rect.width = createSize.x;
  133. if (GUI.Button(rect, createLabel))
  134. {
  135. vcam = CreatePassiveVcamFromSceneView();
  136. vcamProperty.exposedReferenceValue = vcam;
  137. }
  138. serializedObject.ApplyModifiedProperties();
  139. }
  140. EditorGUI.BeginChangeCheck();
  141. DrawRemainingPropertiesInInspector();
  142. if (vcam != null)
  143. DrawSubeditors(vcam);
  144. // by default timeline rebuilds the entire graph when something changes,
  145. // but if a property of the virtual camera changes, we only need to re-evaluate the timeline.
  146. // this prevents flicker on post processing updates
  147. if (EditorGUI.EndChangeCheck())
  148. {
  149. TimelineEditor.Refresh(RefreshReason.SceneNeedsUpdate);
  150. GUI.changed = false;
  151. }
  152. }
  153. void DrawSubeditors(CinemachineVirtualCameraBase vcam)
  154. {
  155. // Create an editor for each of the cinemachine virtual cam and its components
  156. GUIStyle foldoutStyle = new GUIStyle(EditorStyles.foldout) { fontStyle = FontStyle.Bold };
  157. UpdateComponentEditors(vcam);
  158. if (m_editors != null)
  159. {
  160. foreach (UnityEditor.Editor e in m_editors)
  161. {
  162. if (e == null || e.target == null || (e.target.hideFlags & HideFlags.HideInInspector) != 0)
  163. continue;
  164. // Separator line - how do you make a thinner one?
  165. GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(1) } );
  166. bool expanded = true;
  167. if (!s_EditorExpanded.TryGetValue(e.target.GetType(), out expanded))
  168. expanded = true;
  169. expanded = EditorGUILayout.Foldout(
  170. expanded, e.target.GetType().Name, true, foldoutStyle);
  171. if (expanded)
  172. e.OnInspectorGUI();
  173. s_EditorExpanded[e.target.GetType()] = expanded;
  174. }
  175. }
  176. }
  177. CinemachineVirtualCameraBase m_cachedReferenceObject;
  178. UnityEditor.Editor[] m_editors = null;
  179. static Dictionary<System.Type, bool> s_EditorExpanded = new Dictionary<System.Type, bool>();
  180. void UpdateComponentEditors(CinemachineVirtualCameraBase obj)
  181. {
  182. MonoBehaviour[] components = null;
  183. if (obj != null)
  184. components = obj.gameObject.GetComponents<MonoBehaviour>();
  185. int numComponents = (components == null) ? 0 : components.Length;
  186. int numEditors = (m_editors == null) ? 0 : m_editors.Length;
  187. if (m_cachedReferenceObject != obj || (numComponents + 1) != numEditors)
  188. {
  189. DestroyComponentEditors();
  190. m_cachedReferenceObject = obj;
  191. if (obj != null)
  192. {
  193. m_editors = new UnityEditor.Editor[components.Length + 1];
  194. CreateCachedEditor(obj.gameObject.GetComponent<Transform>(), null, ref m_editors[0]);
  195. for (int i = 0; i < components.Length; ++i)
  196. CreateCachedEditor(components[i], null, ref m_editors[i + 1]);
  197. }
  198. }
  199. }
  200. void DestroyComponentEditors()
  201. {
  202. m_cachedReferenceObject = null;
  203. if (m_editors != null)
  204. {
  205. for (int i = 0; i < m_editors.Length; ++i)
  206. {
  207. if (m_editors[i] != null)
  208. UnityEngine.Object.DestroyImmediate(m_editors[i]);
  209. m_editors[i] = null;
  210. }
  211. m_editors = null;
  212. }
  213. }
  214. }
  215. //}
  216. #endif