CinemachineFramingTransposerEditor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. using UnityEngine;
  2. using UnityEditor;
  3. using Cinemachine.Utility;
  4. using System.Collections.Generic;
  5. namespace Cinemachine.Editor
  6. {
  7. [CustomEditor(typeof(CinemachineFramingTransposer))]
  8. [CanEditMultipleObjects]
  9. internal class CinemachineFramingTransposerEditor : BaseEditor<CinemachineFramingTransposer>
  10. {
  11. CinemachineScreenComposerGuides m_ScreenGuideEditor;
  12. GameViewEventCatcher m_GameViewEventCatcher;
  13. /// <summary>Get the property names to exclude in the inspector.</summary>
  14. /// <param name="excluded">Add the names to this list</param>
  15. protected override void GetExcludedPropertiesInInspector(List<string> excluded)
  16. {
  17. base.GetExcludedPropertiesInInspector(excluded);
  18. if (Target.m_UnlimitedSoftZone)
  19. {
  20. excluded.Add(FieldPath(x => x.m_SoftZoneWidth));
  21. excluded.Add(FieldPath(x => x.m_SoftZoneHeight));
  22. excluded.Add(FieldPath(x => x.m_BiasX));
  23. excluded.Add(FieldPath(x => x.m_BiasY));
  24. }
  25. ICinemachineTargetGroup group = Target.AbstractFollowTargetGroup;
  26. if (group == null || Target.m_GroupFramingMode == CinemachineFramingTransposer.FramingMode.None)
  27. {
  28. excluded.Add(FieldPath(x => x.m_GroupFramingSize));
  29. excluded.Add(FieldPath(x => x.m_AdjustmentMode));
  30. excluded.Add(FieldPath(x => x.m_MaxDollyIn));
  31. excluded.Add(FieldPath(x => x.m_MaxDollyOut));
  32. excluded.Add(FieldPath(x => x.m_MinimumDistance));
  33. excluded.Add(FieldPath(x => x.m_MaximumDistance));
  34. excluded.Add(FieldPath(x => x.m_MinimumFOV));
  35. excluded.Add(FieldPath(x => x.m_MaximumFOV));
  36. excluded.Add(FieldPath(x => x.m_MinimumOrthoSize));
  37. excluded.Add(FieldPath(x => x.m_MaximumOrthoSize));
  38. if (group == null)
  39. excluded.Add(FieldPath(x => x.m_GroupFramingMode));
  40. }
  41. else
  42. {
  43. CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(Target.VirtualCamera);
  44. bool ortho = brain != null ? brain.OutputCamera.orthographic : false;
  45. if (ortho)
  46. {
  47. excluded.Add(FieldPath(x => x.m_AdjustmentMode));
  48. excluded.Add(FieldPath(x => x.m_MaxDollyIn));
  49. excluded.Add(FieldPath(x => x.m_MaxDollyOut));
  50. excluded.Add(FieldPath(x => x.m_MinimumDistance));
  51. excluded.Add(FieldPath(x => x.m_MaximumDistance));
  52. excluded.Add(FieldPath(x => x.m_MinimumFOV));
  53. excluded.Add(FieldPath(x => x.m_MaximumFOV));
  54. }
  55. else
  56. {
  57. excluded.Add(FieldPath(x => x.m_MinimumOrthoSize));
  58. excluded.Add(FieldPath(x => x.m_MaximumOrthoSize));
  59. switch (Target.m_AdjustmentMode)
  60. {
  61. case CinemachineFramingTransposer.AdjustmentMode.DollyOnly:
  62. excluded.Add(FieldPath(x => x.m_MinimumFOV));
  63. excluded.Add(FieldPath(x => x.m_MaximumFOV));
  64. break;
  65. case CinemachineFramingTransposer.AdjustmentMode.ZoomOnly:
  66. excluded.Add(FieldPath(x => x.m_MaxDollyIn));
  67. excluded.Add(FieldPath(x => x.m_MaxDollyOut));
  68. excluded.Add(FieldPath(x => x.m_MinimumDistance));
  69. excluded.Add(FieldPath(x => x.m_MaximumDistance));
  70. break;
  71. default:
  72. break;
  73. }
  74. }
  75. }
  76. }
  77. protected virtual void OnEnable()
  78. {
  79. m_ScreenGuideEditor = new CinemachineScreenComposerGuides();
  80. m_ScreenGuideEditor.GetHardGuide = () => { return Target.HardGuideRect; };
  81. m_ScreenGuideEditor.GetSoftGuide = () => { return Target.SoftGuideRect; };
  82. m_ScreenGuideEditor.SetHardGuide = (Rect r) => { Target.HardGuideRect = r; };
  83. m_ScreenGuideEditor.SetSoftGuide = (Rect r) => { Target.SoftGuideRect = r; };
  84. m_ScreenGuideEditor.Target = () => { return serializedObject; };
  85. m_GameViewEventCatcher = new GameViewEventCatcher();
  86. m_GameViewEventCatcher.OnEnable();
  87. CinemachineDebug.OnGUIHandlers -= OnGUI;
  88. CinemachineDebug.OnGUIHandlers += OnGUI;
  89. if (CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides)
  90. InspectorUtility.RepaintGameView();
  91. #if UNITY_2021_2_OR_NEWER
  92. CinemachineSceneToolUtility.RegisterTool(typeof(FollowOffsetTool));
  93. CinemachineSceneToolUtility.RegisterTool(typeof(TrackedObjectOffsetTool));
  94. #endif
  95. }
  96. protected virtual void OnDisable()
  97. {
  98. m_GameViewEventCatcher.OnDisable();
  99. CinemachineDebug.OnGUIHandlers -= OnGUI;
  100. if (CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides)
  101. InspectorUtility.RepaintGameView();
  102. #if UNITY_2021_2_OR_NEWER
  103. CinemachineSceneToolUtility.UnregisterTool(typeof(FollowOffsetTool));
  104. CinemachineSceneToolUtility.UnregisterTool(typeof(TrackedObjectOffsetTool));
  105. #endif
  106. }
  107. public override void OnInspectorGUI()
  108. {
  109. BeginInspector();
  110. bool needWarning = false;
  111. for (int i = 0; !needWarning && i < targets.Length; ++i)
  112. needWarning = (targets[i] as CinemachineFramingTransposer).FollowTarget == null;
  113. if (needWarning)
  114. EditorGUILayout.HelpBox(
  115. "Framing Transposer requires a Follow target. "
  116. + "Change Body to Do Nothing if you don't want a Follow target.",
  117. MessageType.Warning);
  118. // First snapshot some settings
  119. Rect oldHard = Target.HardGuideRect;
  120. Rect oldSoft = Target.SoftGuideRect;
  121. // Draw the properties
  122. DrawRemainingPropertiesInInspector();
  123. m_ScreenGuideEditor.SetNewBounds(oldHard, oldSoft, Target.HardGuideRect, Target.SoftGuideRect);
  124. }
  125. protected virtual void OnGUI()
  126. {
  127. // Draw the camera guides
  128. if (Target == null || !CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides)
  129. return;
  130. // If inspector is collapsed in the vcam editor, don't draw the guides
  131. if (!VcamStageEditor.ActiveEditorRegistry.IsActiveEditor(this))
  132. return;
  133. CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(Target.VirtualCamera);
  134. if (brain == null || (brain.OutputCamera.activeTexture != null && CinemachineCore.Instance.BrainCount > 1))
  135. return;
  136. bool isLive = targets.Length <= 1 && brain.IsLive(Target.VirtualCamera, true);
  137. // Screen guides
  138. m_ScreenGuideEditor.OnGUI_DrawGuides(isLive, brain.OutputCamera, Target.VcamState.Lens, !Target.m_UnlimitedSoftZone);
  139. // Draw an on-screen gizmo for the target
  140. if (Target.FollowTarget != null && isLive)
  141. {
  142. Vector3 targetScreenPosition = brain.OutputCamera.WorldToScreenPoint(Target.TrackedPoint);
  143. if (targetScreenPosition.z > 0)
  144. {
  145. targetScreenPosition.y = Screen.height - targetScreenPosition.y;
  146. GUI.color = CinemachineSettings.ComposerSettings.TargetColour;
  147. Rect r = new Rect(targetScreenPosition, Vector2.zero);
  148. float size = (CinemachineSettings.ComposerSettings.TargetSize
  149. + CinemachineScreenComposerGuides.kGuideBarWidthPx) / 2;
  150. GUI.DrawTexture(r.Inflated(new Vector2(size, size)), Texture2D.whiteTexture);
  151. size -= CinemachineScreenComposerGuides.kGuideBarWidthPx;
  152. if (size > 0)
  153. {
  154. Vector4 overlayOpacityScalar
  155. = new Vector4(1f, 1f, 1f, CinemachineSettings.ComposerSettings.OverlayOpacity);
  156. GUI.color = Color.black * overlayOpacityScalar;
  157. GUI.DrawTexture(r.Inflated(new Vector2(size, size)), Texture2D.whiteTexture);
  158. }
  159. }
  160. }
  161. }
  162. [DrawGizmo(GizmoType.Active | GizmoType.InSelectionHierarchy, typeof(CinemachineFramingTransposer))]
  163. private static void DrawGroupComposerGizmos(CinemachineFramingTransposer target, GizmoType selectionType)
  164. {
  165. // Show the group bounding box, as viewed from the camera position
  166. if (target.AbstractFollowTargetGroup != null
  167. && target.m_GroupFramingMode != CinemachineFramingTransposer.FramingMode.None)
  168. {
  169. Matrix4x4 m = Gizmos.matrix;
  170. Bounds b = target.LastBounds;
  171. Gizmos.matrix = target.LastBoundsMatrix;
  172. Gizmos.color = Color.yellow;
  173. if (target.VcamState.Lens.Orthographic)
  174. Gizmos.DrawWireCube(b.center, b.size);
  175. else
  176. {
  177. float z = b.center.z;
  178. Vector3 e = b.extents;
  179. Gizmos.DrawFrustum(
  180. Vector3.zero,
  181. Mathf.Atan2(e.y, z) * Mathf.Rad2Deg * 2,
  182. z + e.z, z - e.z, e.x / e.y);
  183. }
  184. Gizmos.matrix = m;
  185. }
  186. }
  187. #if UNITY_2021_2_OR_NEWER
  188. void OnSceneGUI()
  189. {
  190. DrawSceneTools();
  191. }
  192. void DrawSceneTools()
  193. {
  194. var framingTransposer = Target;
  195. if (framingTransposer == null || !framingTransposer.IsValid)
  196. {
  197. return;
  198. }
  199. if (CinemachineSceneToolUtility.IsToolActive(typeof(TrackedObjectOffsetTool)))
  200. {
  201. CinemachineSceneToolHelpers.TrackedObjectOffsetTool(framingTransposer,
  202. new SerializedObject(framingTransposer).FindProperty(() => framingTransposer.m_TrackedObjectOffset));
  203. }
  204. else if (CinemachineSceneToolUtility.IsToolActive(typeof(FollowOffsetTool)))
  205. {
  206. var originalColor = Handles.color;
  207. var camPos = framingTransposer.VcamState.RawPosition;
  208. var targetForward = framingTransposer.VirtualCamera.State.FinalOrientation * Vector3.forward;
  209. EditorGUI.BeginChangeCheck();
  210. Handles.color = CinemachineSceneToolHelpers.HelperLineDefaultColor;
  211. var cdHandleId = GUIUtility.GetControlID(FocusType.Passive);
  212. var newHandlePosition = Handles.Slider(cdHandleId, camPos, targetForward,
  213. CinemachineSceneToolHelpers.CubeHandleCapSize(camPos), Handles.CubeHandleCap, 0.5f);
  214. if (EditorGUI.EndChangeCheck())
  215. {
  216. // Modify via SerializedProperty for OnValidate to get called automatically, and scene repainting too
  217. var so = new SerializedObject(framingTransposer);
  218. var prop = so.FindProperty(() => framingTransposer.m_CameraDistance);
  219. prop.floatValue -= CinemachineSceneToolHelpers.SliderHandleDelta(newHandlePosition, camPos, targetForward);
  220. so.ApplyModifiedProperties();
  221. }
  222. var cameraDistanceHandleIsDragged = GUIUtility.hotControl == cdHandleId;
  223. var cameraDistanceHandleIsUsedOrHovered = cameraDistanceHandleIsDragged ||
  224. HandleUtility.nearestControl == cdHandleId;
  225. if (cameraDistanceHandleIsUsedOrHovered)
  226. {
  227. CinemachineSceneToolHelpers.DrawLabel(camPos,
  228. "Camera Distance (" + framingTransposer.m_CameraDistance.ToString("F1") + ")");
  229. }
  230. Handles.color = cameraDistanceHandleIsUsedOrHovered ?
  231. Handles.selectedColor : CinemachineSceneToolHelpers.HelperLineDefaultColor;
  232. Handles.DrawLine(camPos,
  233. framingTransposer.FollowTarget.position + framingTransposer.m_TrackedObjectOffset);
  234. CinemachineSceneToolHelpers.SoloOnDrag(cameraDistanceHandleIsDragged, framingTransposer.VirtualCamera,
  235. cdHandleId);
  236. Handles.color = originalColor;
  237. }
  238. }
  239. #endif
  240. }
  241. }