CinemachineMixingCamera.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. using UnityEngine;
  2. using Cinemachine.Utility;
  3. using System.Collections.Generic;
  4. namespace Cinemachine
  5. {
  6. /// <summary>
  7. /// CinemachineMixingCamera is a "manager camera" that takes on the state of
  8. /// the weighted average of the states of its child virtual cameras.
  9. ///
  10. /// A fixed number of slots are made available for cameras, rather than a dynamic array.
  11. /// We do it this way in order to support weight animation from the Timeline.
  12. /// Timeline cannot animate array elements.
  13. /// </summary>
  14. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  15. [DisallowMultipleComponent]
  16. [ExecuteAlways]
  17. [ExcludeFromPreset]
  18. [AddComponentMenu("Cinemachine/CinemachineMixingCamera")]
  19. [HelpURL(Documentation.BaseURL + "manual/CinemachineMixingCamera.html")]
  20. public class CinemachineMixingCamera : CinemachineVirtualCameraBase
  21. {
  22. /// <summary>The maximum number of tracked cameras. If you want to add
  23. /// more cameras, do it here in the source code, and be sure to add the
  24. /// extra member variables and to make the appropriate changes in
  25. /// GetWeight() and SetWeight().
  26. /// The inspector will figure itself out based on this value.</summary>
  27. public const int MaxCameras = 8;
  28. /// <summary>Weight of the first tracked camera</summary>
  29. [Tooltip("The weight of the first tracked camera")]
  30. public float m_Weight0 = 0.5f;
  31. /// <summary>Weight of the second tracked camera</summary>
  32. [Tooltip("The weight of the second tracked camera")]
  33. public float m_Weight1 = 0.5f;
  34. /// <summary>Weight of the third tracked camera</summary>
  35. [Tooltip("The weight of the third tracked camera")]
  36. public float m_Weight2 = 0.5f;
  37. /// <summary>Weight of the fourth tracked camera</summary>
  38. [Tooltip("The weight of the fourth tracked camera")]
  39. public float m_Weight3 = 0.5f;
  40. /// <summary>Weight of the fifth tracked camera</summary>
  41. [Tooltip("The weight of the fifth tracked camera")]
  42. public float m_Weight4 = 0.5f;
  43. /// <summary>Weight of the sixth tracked camera</summary>
  44. [Tooltip("The weight of the sixth tracked camera")]
  45. public float m_Weight5 = 0.5f;
  46. /// <summary>Weight of the seventh tracked camera</summary>
  47. [Tooltip("The weight of the seventh tracked camera")]
  48. public float m_Weight6 = 0.5f;
  49. /// <summary>Weight of the eighth tracked camera</summary>
  50. [Tooltip("The weight of the eighth tracked camera")]
  51. public float m_Weight7 = 0.5f;
  52. /// <summary>Get the weight of the child at an index.</summary>
  53. /// <param name="index">The child index. Only immediate CinemachineVirtualCameraBase
  54. /// children are counted.</param>
  55. /// <returns>The weight of the camera. Valid only if camera is active and enabled.</returns>
  56. public float GetWeight(int index)
  57. {
  58. switch (index)
  59. {
  60. case 0: return m_Weight0;
  61. case 1: return m_Weight1;
  62. case 2: return m_Weight2;
  63. case 3: return m_Weight3;
  64. case 4: return m_Weight4;
  65. case 5: return m_Weight5;
  66. case 6: return m_Weight6;
  67. case 7: return m_Weight7;
  68. }
  69. Debug.LogError("CinemachineMixingCamera: Invalid index: " + index);
  70. return 0;
  71. }
  72. /// <summary>Set the weight of the child at an index.</summary>
  73. /// <param name="index">The child index. Only immediate CinemachineVirtualCameraBase
  74. /// children are counted.</param>
  75. /// <param name="w">The weight to set. Can be any non-negative number.</param>
  76. public void SetWeight(int index, float w)
  77. {
  78. switch (index)
  79. {
  80. case 0: m_Weight0 = w; return;
  81. case 1: m_Weight1 = w; return;
  82. case 2: m_Weight2 = w; return;
  83. case 3: m_Weight3 = w; return;
  84. case 4: m_Weight4 = w; return;
  85. case 5: m_Weight5 = w; return;
  86. case 6: m_Weight6 = w; return;
  87. case 7: m_Weight7 = w; return;
  88. }
  89. Debug.LogError("CinemachineMixingCamera: Invalid index: " + index);
  90. }
  91. /// <summary>Get the weight of the child CinemachineVirtualCameraBase.</summary>
  92. /// <param name="vcam">The child camera.</param>
  93. /// <returns>The weight of the camera. Valid only if camera is active and enabled.</returns>
  94. public float GetWeight(CinemachineVirtualCameraBase vcam)
  95. {
  96. ValidateListOfChildren();
  97. int index;
  98. if (m_indexMap.TryGetValue(vcam, out index))
  99. return GetWeight(index);
  100. Debug.LogError("CinemachineMixingCamera: Invalid child: "
  101. + ((vcam != null) ? vcam.Name : "(null)"));
  102. return 0;
  103. }
  104. /// <summary>Set the weight of the child CinemachineVirtualCameraBase.</summary>
  105. /// <param name="vcam">The child camera.</param>
  106. /// <param name="w">The weight to set. Can be any non-negative number.</param>
  107. public void SetWeight(CinemachineVirtualCameraBase vcam, float w)
  108. {
  109. ValidateListOfChildren();
  110. int index;
  111. if (m_indexMap.TryGetValue(vcam, out index))
  112. SetWeight(index, w);
  113. else
  114. Debug.LogError("CinemachineMixingCamera: Invalid child: "
  115. + ((vcam != null) ? vcam.Name : "(null)"));
  116. }
  117. /// <summary>Blended camera state</summary>
  118. private CameraState m_State = CameraState.Default;
  119. /// <summary>Get the current "best" child virtual camera, which is nominally
  120. /// the one with the greatest weight.</summary>
  121. private ICinemachineCamera LiveChild { get; set; }
  122. /// <summary>The blended CameraState</summary>
  123. public override CameraState State { get { return m_State; } }
  124. /// <summary>Not used</summary>
  125. override public Transform LookAt { get; set; }
  126. /// <summary>Not used</summary>
  127. override public Transform Follow { get; set; }
  128. /// <summary>This is called to notify the vcam that a target got warped,
  129. /// so that the vcam can update its internal state to make the camera
  130. /// also warp seamlessy.</summary>
  131. /// <param name="target">The object that was warped</param>
  132. /// <param name="positionDelta">The amount the target's position changed</param>
  133. public override void OnTargetObjectWarped(Transform target, Vector3 positionDelta)
  134. {
  135. ValidateListOfChildren();
  136. foreach (var vcam in m_ChildCameras)
  137. vcam.OnTargetObjectWarped(target, positionDelta);
  138. base.OnTargetObjectWarped(target, positionDelta);
  139. }
  140. /// <summary>
  141. /// Force the virtual camera to assume a given position and orientation
  142. /// </summary>
  143. /// <param name="pos">Worldspace pposition to take</param>
  144. /// <param name="rot">Worldspace orientation to take</param>
  145. public override void ForceCameraPosition(Vector3 pos, Quaternion rot)
  146. {
  147. ValidateListOfChildren();
  148. foreach (var vcam in m_ChildCameras)
  149. vcam.ForceCameraPosition(pos, rot);
  150. base.ForceCameraPosition(pos, rot);
  151. }
  152. /// <summary>Makes sure the internal child cache is up to date</summary>
  153. protected override void OnEnable()
  154. {
  155. base.OnEnable();
  156. InvalidateListOfChildren();
  157. }
  158. /// <summary>Makes sure the internal child cache is up to date</summary>
  159. public void OnTransformChildrenChanged()
  160. {
  161. InvalidateListOfChildren();
  162. }
  163. /// <summary>Makes sure the weights are non-negative</summary>
  164. protected override void OnValidate()
  165. {
  166. base.OnValidate();
  167. for (int i = 0; i < MaxCameras; ++i)
  168. SetWeight(i, Mathf.Max(0, GetWeight(i)));
  169. }
  170. /// <summary>Check whether the vcam a live child of this camera.</summary>
  171. /// <param name="vcam">The Virtual Camera to check</param>
  172. /// <param name="dominantChildOnly">If truw, will only return true if this vcam is the dominat live child</param>
  173. /// <returns>True if the vcam is currently actively influencing the state of this vcam</returns>
  174. public override bool IsLiveChild(ICinemachineCamera vcam, bool dominantChildOnly = false)
  175. {
  176. CinemachineVirtualCameraBase[] children = ChildCameras;
  177. for (int i = 0; i < MaxCameras && i < children.Length; ++i)
  178. if ((ICinemachineCamera)children[i] == vcam)
  179. return GetWeight(i) > UnityVectorExtensions.Epsilon && children[i].isActiveAndEnabled;
  180. return false;
  181. }
  182. private CinemachineVirtualCameraBase[] m_ChildCameras;
  183. private Dictionary<CinemachineVirtualCameraBase, int> m_indexMap;
  184. /// <summary>Get the cached list of child cameras.
  185. /// These are just the immediate children in the hierarchy.
  186. /// Note: only the first entries of this list participate in the
  187. /// final blend, up to MaxCameras</summary>
  188. public CinemachineVirtualCameraBase[] ChildCameras
  189. {
  190. get { ValidateListOfChildren(); return m_ChildCameras; }
  191. }
  192. /// <summary>Invalidate the cached list of child cameras.</summary>
  193. protected void InvalidateListOfChildren()
  194. {
  195. m_ChildCameras = null;
  196. m_indexMap = null;
  197. LiveChild = null;
  198. }
  199. /// <summary>Rebuild the cached list of child cameras.</summary>
  200. protected void ValidateListOfChildren()
  201. {
  202. if (m_ChildCameras != null)
  203. return;
  204. m_indexMap = new Dictionary<CinemachineVirtualCameraBase, int>();
  205. List<CinemachineVirtualCameraBase> list = new List<CinemachineVirtualCameraBase>();
  206. CinemachineVirtualCameraBase[] kids
  207. = GetComponentsInChildren<CinemachineVirtualCameraBase>(true);
  208. foreach (CinemachineVirtualCameraBase k in kids)
  209. {
  210. if (k.transform.parent == transform)
  211. {
  212. int index = list.Count;
  213. list.Add(k);
  214. if (index < MaxCameras)
  215. m_indexMap.Add(k, index);
  216. }
  217. }
  218. m_ChildCameras = list.ToArray();
  219. }
  220. /// <summary>Notification that this virtual camera is going live.</summary>
  221. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  222. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  223. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  224. public override void OnTransitionFromCamera(
  225. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
  226. {
  227. base.OnTransitionFromCamera(fromCam, worldUp, deltaTime);
  228. InvokeOnTransitionInExtensions(fromCam, worldUp, deltaTime);
  229. CinemachineVirtualCameraBase[] children = ChildCameras;
  230. for (int i = 0; i < MaxCameras && i < children.Length; ++i)
  231. children[i].OnTransitionFromCamera(fromCam, worldUp, deltaTime);
  232. InternalUpdateCameraState(worldUp, deltaTime);
  233. }
  234. /// <summary>Internal use only. Do not call this methid.
  235. /// Called by CinemachineCore at designated update time
  236. /// so the vcam can position itself and track its targets. This implementation
  237. /// computes and caches the weighted blend of the tracked cameras.</summary>
  238. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  239. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
  240. public override void InternalUpdateCameraState(Vector3 worldUp, float deltaTime)
  241. {
  242. CinemachineVirtualCameraBase[] children = ChildCameras;
  243. LiveChild = null;
  244. float highestWeight = 0;
  245. float totalWeight = 0;
  246. for (int i = 0; i < MaxCameras && i < children.Length; ++i)
  247. {
  248. CinemachineVirtualCameraBase vcam = children[i];
  249. if (vcam.isActiveAndEnabled)
  250. {
  251. float weight = Mathf.Max(0, GetWeight(i));
  252. if (weight > UnityVectorExtensions.Epsilon)
  253. {
  254. totalWeight += weight;
  255. if (totalWeight == weight)
  256. m_State = vcam.State;
  257. else
  258. m_State = CameraState.Lerp(m_State, vcam.State, weight / totalWeight);
  259. if (weight > highestWeight)
  260. {
  261. highestWeight = weight;
  262. LiveChild = vcam;
  263. }
  264. }
  265. }
  266. }
  267. InvokePostPipelineStageCallback(
  268. this, CinemachineCore.Stage.Finalize, ref m_State, deltaTime);
  269. }
  270. }
  271. }