CinemachineNewFreeLook.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. #if CINEMACHINE_EXPERIMENTAL_VCAM
  2. using UnityEngine;
  3. using Cinemachine.Utility;
  4. using System;
  5. namespace Cinemachine
  6. {
  7. /// <summary>
  8. ///
  9. /// NOTE: THIS CLASS IS EXPERIMENTAL, AND NOT FOR PUBLIC USE
  10. ///
  11. /// Lighter-weight version of the CinemachineFreeLook, with extra radial axis.
  12. ///
  13. /// A Cinemachine Camera geared towards a 3rd person camera experience.
  14. /// The camera orbits around its subject with three separate camera rigs defining
  15. /// rings around the target. Each rig has its own radius, height offset, composer,
  16. /// and lens settings.
  17. /// Depending on the camera's position along the spline connecting these three rigs,
  18. /// these settings are interpolated to give the final camera position and state.
  19. /// </summary>
  20. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  21. [DisallowMultipleComponent]
  22. [ExecuteAlways]
  23. [AddComponentMenu("Cinemachine/CinemachineNewFreeLook")]
  24. [SaveDuringPlay]
  25. public class CinemachineNewFreeLook : CinemachineNewVirtualCamera
  26. {
  27. /// <summary>The Vertical axis. Value is 0..1. Chooses how to blend the child rigs</summary>
  28. [Tooltip("The Vertical axis. Value is 0..1. 0.5 is the middle rig. Chooses how to blend the child rigs")]
  29. [AxisStateProperty]
  30. public AxisState m_VerticalAxis = new AxisState(0, 1, false, true, 2f, 0.2f, 0.1f, "Mouse Y", false);
  31. [Tooltip("The Radial axis. Value is the base radius of the orbits")]
  32. [AxisStateProperty]
  33. public AxisState m_RadialAxis = new AxisState(1, 1, false, false, 100, 0f, 0f, "Mouse ScrollWheel", false);
  34. /// <summary>Defines the height and radius for an orbit</summary>
  35. [Serializable]
  36. public struct Orbit
  37. {
  38. /// <summary>Height relative to target</summary>
  39. public float m_Height;
  40. /// <summary>Radius of orbit</summary>
  41. public float m_Radius;
  42. }
  43. /// <summary>Order is Top, Middle, Bottom</summary>
  44. public Orbit[] m_Orbits = new Orbit[3];
  45. /// <summary></summary>
  46. [Tooltip("Controls how taut is the line that connects the rigs' orbits, which determines final placement on the Y axis")]
  47. [Range(0f, 1f)]
  48. public float m_SplineCurvature;
  49. /// <summary>Identifiers for accessing override settings for top and bottom rigs</summary>
  50. public enum RigID { Top, Bottom };
  51. /// <summary>Override settings for top and bottom rigs</summary>
  52. [Serializable]
  53. public class Rig : ISerializationCallbackReceiver
  54. {
  55. public bool m_CustomLens;
  56. public LensSettings m_Lens;
  57. public bool m_CustomBody;
  58. public TransposerSettings m_Body;
  59. public bool m_CustomAim;
  60. public ComposerSettings m_Aim;
  61. public bool m_CustomNoise;
  62. public PerlinNoiseSettings m_Noise;
  63. public void Validate()
  64. {
  65. if (m_Lens.FieldOfView == 0)
  66. m_Lens = LensSettings.Default;
  67. m_Lens.Validate();
  68. }
  69. /// <summary>Blendable settings for Transposer Transposer</summary>
  70. [Serializable] public class TransposerSettings
  71. {
  72. [Range(0f, 20f)] public float m_XDamping;
  73. [Range(0f, 20f)] public float m_YDamping;
  74. [Range(0f, 20f)] public float m_ZDamping;
  75. [Range(0f, 20f)] public float m_PitchDamping;
  76. [Range(0f, 20f)] public float m_YawDamping;
  77. [Range(0f, 20f)] public float m_RollDamping;
  78. internal void Lerp(CinemachineTransposer o, float t)
  79. {
  80. o.m_XDamping = Mathf.Lerp(o.m_XDamping, m_XDamping, t);
  81. o.m_YDamping = Mathf.Lerp(o.m_YDamping, m_YDamping, t);
  82. o.m_ZDamping = Mathf.Lerp(o.m_ZDamping, m_ZDamping, t);
  83. o.m_PitchDamping = Mathf.Lerp(o.m_PitchDamping, m_PitchDamping, t);
  84. o.m_YawDamping = Mathf.Lerp(o.m_YawDamping, m_YawDamping, t);
  85. o.m_RollDamping = Mathf.Lerp(o.m_RollDamping, m_RollDamping, t);
  86. }
  87. internal void PullFrom(CinemachineTransposer o)
  88. {
  89. m_XDamping = o.m_XDamping;
  90. m_YDamping = o.m_YDamping;
  91. m_ZDamping = o.m_ZDamping;
  92. m_PitchDamping = o.m_PitchDamping;
  93. m_YawDamping = o.m_YawDamping;
  94. m_RollDamping = o.m_RollDamping;
  95. }
  96. internal void PushTo(CinemachineTransposer o)
  97. {
  98. o.m_XDamping = m_XDamping;
  99. o.m_YDamping = m_YDamping;
  100. o.m_ZDamping = m_ZDamping;
  101. o.m_PitchDamping =m_PitchDamping;
  102. o.m_YawDamping = m_YawDamping;
  103. o.m_RollDamping = m_RollDamping;
  104. }
  105. }
  106. /// <summary>Blendable settings for Composer</summary>
  107. [Serializable] public class ComposerSettings
  108. {
  109. public Vector3 m_LookAtOffset;
  110. [Space]
  111. [Range(0f, 20)] public float m_HorizontalDamping;
  112. [Range(0f, 20)] public float m_VerticalDamping;
  113. [Space]
  114. [Range(0f, 1f)] public float m_ScreenX;
  115. [Range(0f, 1f)] public float m_ScreenY;
  116. [Range(0f, 1f)] public float m_DeadZoneWidth;
  117. [Range(0f, 1f)] public float m_DeadZoneHeight;
  118. [Range(0f, 2f)] public float m_SoftZoneWidth;
  119. [Range(0f, 2f)] public float m_SoftZoneHeight;
  120. [Range(-0.5f, 0.5f)] public float m_BiasX;
  121. [Range(-0.5f, 0.5f)] public float m_BiasY;
  122. internal void Lerp(CinemachineComposer c, float t)
  123. {
  124. c.m_TrackedObjectOffset = Vector3.Lerp(c.m_TrackedObjectOffset, m_LookAtOffset, t);
  125. c.m_HorizontalDamping = Mathf.Lerp(c.m_HorizontalDamping, m_HorizontalDamping, t);
  126. c.m_VerticalDamping = Mathf.Lerp(c.m_VerticalDamping, m_VerticalDamping, t);
  127. c.m_ScreenX = Mathf.Lerp(c.m_ScreenX, m_ScreenX, t);
  128. c.m_ScreenY = Mathf.Lerp(c.m_ScreenY, m_ScreenY, t);
  129. c.m_DeadZoneWidth = Mathf.Lerp(c.m_DeadZoneWidth, m_DeadZoneWidth, t);
  130. c.m_DeadZoneHeight = Mathf.Lerp(c.m_DeadZoneHeight, m_DeadZoneHeight, t);
  131. c.m_SoftZoneWidth = Mathf.Lerp(c.m_SoftZoneWidth, m_SoftZoneWidth, t);
  132. c.m_SoftZoneHeight = Mathf.Lerp(c.m_SoftZoneHeight, m_SoftZoneHeight, t);
  133. c.m_BiasX = Mathf.Lerp(c.m_BiasX, m_BiasX, t);
  134. c.m_BiasY = Mathf.Lerp(c.m_BiasY, m_BiasY, t);
  135. }
  136. internal void PullFrom(CinemachineComposer c)
  137. {
  138. m_LookAtOffset = c.m_TrackedObjectOffset;
  139. m_HorizontalDamping = c.m_HorizontalDamping;
  140. m_VerticalDamping = c.m_VerticalDamping;
  141. m_ScreenX = c.m_ScreenX;
  142. m_ScreenY = c.m_ScreenY;
  143. m_DeadZoneWidth = c.m_DeadZoneWidth;
  144. m_DeadZoneHeight = c.m_DeadZoneHeight;
  145. m_SoftZoneWidth = c.m_SoftZoneWidth;
  146. m_SoftZoneHeight = c.m_SoftZoneHeight;
  147. m_BiasX = c.m_BiasX;
  148. m_BiasY = c.m_BiasY;
  149. }
  150. internal void PushTo(CinemachineComposer c)
  151. {
  152. c.m_TrackedObjectOffset = m_LookAtOffset;
  153. c.m_HorizontalDamping = m_HorizontalDamping;
  154. c.m_VerticalDamping = m_VerticalDamping;
  155. c.m_ScreenX = m_ScreenX;
  156. c.m_ScreenY = m_ScreenY;
  157. c.m_DeadZoneWidth = m_DeadZoneWidth;
  158. c.m_DeadZoneHeight = m_DeadZoneHeight;
  159. c.m_SoftZoneWidth = m_SoftZoneWidth;
  160. c.m_SoftZoneHeight = m_SoftZoneHeight;
  161. c.m_BiasX = m_BiasX;
  162. c.m_BiasY = m_BiasY;
  163. }
  164. }
  165. /// <summary>Blendable settings for CinemachineBasicMultiChannelPerlin</summary>
  166. [Serializable] public class PerlinNoiseSettings
  167. {
  168. public float m_AmplitudeGain;
  169. public float m_FrequencyGain;
  170. internal void Lerp(CinemachineBasicMultiChannelPerlin p, float t)
  171. {
  172. p.m_AmplitudeGain = Mathf.Lerp(p.m_AmplitudeGain, m_AmplitudeGain, t);
  173. p.m_FrequencyGain =Mathf.Lerp(p.m_FrequencyGain, m_FrequencyGain, t);
  174. }
  175. internal void PullFrom(CinemachineBasicMultiChannelPerlin p)
  176. {
  177. m_AmplitudeGain = p.m_AmplitudeGain;
  178. m_FrequencyGain = p.m_FrequencyGain;
  179. }
  180. internal void PushTo(CinemachineBasicMultiChannelPerlin p)
  181. {
  182. p.m_AmplitudeGain = m_AmplitudeGain;
  183. p.m_FrequencyGain = m_FrequencyGain;
  184. }
  185. }
  186. // This prevents the sensor size from dirtying the scene in the event of aspect ratio change
  187. void ISerializationCallbackReceiver.OnBeforeSerialize()
  188. {
  189. if (!m_Lens.IsPhysicalCamera)
  190. m_Lens.SensorSize = Vector2.one;
  191. }
  192. void ISerializationCallbackReceiver.OnAfterDeserialize() {}
  193. }
  194. [SerializeField]
  195. internal Rig[] m_Rigs = new Rig[2] { new Rig(), new Rig() };
  196. /// <summary>Accessor for rig override settings</summary>
  197. public Rig RigSettings(RigID rig) { return m_Rigs[(int)rig]; }
  198. /// Easy access to the transposer (may be null)
  199. CinemachineTransposer Transposer
  200. {
  201. get { return ComponentCache[(int)CinemachineCore.Stage.Body] as CinemachineTransposer; }
  202. }
  203. /// <summary>Enforce bounds for fields, when changed in inspector.</summary>
  204. protected override void OnValidate()
  205. {
  206. base.OnValidate();
  207. for (int i = 0; i < m_Rigs.Length; ++i)
  208. m_Rigs[i].Validate();
  209. }
  210. private void Awake()
  211. {
  212. m_VerticalAxis.HasRecentering = true;
  213. m_RadialAxis.HasRecentering = false;
  214. }
  215. /// <summary>Updates the child rig cache</summary>
  216. protected override void OnEnable()
  217. {
  218. base.OnEnable();
  219. UpdateInputAxisProvider();
  220. }
  221. /// <summary>
  222. /// API for the inspector. Internal use only
  223. /// </summary>
  224. public void UpdateInputAxisProvider()
  225. {
  226. m_VerticalAxis.SetInputAxisProvider(0, null);
  227. m_RadialAxis.SetInputAxisProvider(1, null);
  228. var provider = GetInputAxisProvider();
  229. if (provider != null)
  230. {
  231. m_VerticalAxis.SetInputAxisProvider(1, provider);
  232. m_RadialAxis.SetInputAxisProvider(2, provider);
  233. }
  234. }
  235. void Reset()
  236. {
  237. DestroyComponents();
  238. #if UNITY_EDITOR
  239. var orbital = UnityEditor.Undo.AddComponent<CinemachineOrbitalTransposer>(gameObject);
  240. UnityEditor.Undo.AddComponent<CinemachineComposer>(gameObject);
  241. #else
  242. var orbital = gameObject.AddComponent<CinemachineOrbitalTransposer>();
  243. gameObject.AddComponent<CinemachineComposer>();
  244. #endif
  245. orbital.HideOffsetInInspector = true;
  246. orbital.m_BindingMode = CinemachineTransposer.BindingMode.SimpleFollowWithWorldUp;
  247. InvalidateComponentCache();
  248. m_Rigs = new Rig[2] { new Rig(), new Rig() };
  249. // Default orbits
  250. m_Orbits = new Orbit[3];
  251. m_Orbits[0].m_Height = 10; m_Orbits[0].m_Radius = 4;
  252. m_Orbits[1].m_Height = 2.5f; m_Orbits[1].m_Radius = 8;
  253. m_Orbits[2].m_Height = -0.5f; m_Orbits[2].m_Radius = 5;
  254. m_SplineCurvature = 0.5f;
  255. }
  256. /// <summary>
  257. /// Force the virtual camera to assume a given position and orientation.
  258. /// Procedural placement then takes over
  259. /// </summary>
  260. /// <param name="pos">Worldspace pposition to take</param>
  261. /// <param name="rot">Worldspace orientation to take</param>
  262. public override void ForceCameraPosition(Vector3 pos, Quaternion rot)
  263. {
  264. base.ForceCameraPosition(pos, rot);
  265. m_VerticalAxis.Value = GetYAxisClosestValue(pos, State.ReferenceUp);
  266. }
  267. /// <summary>If we are transitioning from another FreeLook, grab the axis values from it.</summary>
  268. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  269. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  270. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  271. public override void OnTransitionFromCamera(
  272. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
  273. {
  274. base.OnTransitionFromCamera(fromCam, worldUp, deltaTime);
  275. InvokeOnTransitionInExtensions(fromCam, worldUp, deltaTime);
  276. m_VerticalAxis.m_Recentering.DoRecentering(ref m_VerticalAxis, -1, 0.5f);
  277. m_VerticalAxis.m_Recentering.CancelRecentering();
  278. if (fromCam != null && m_Transitions.m_InheritPosition
  279. && !CinemachineCore.Instance.IsLiveInBlend(this))
  280. {
  281. // Note: horizontal axis already taken care of by base class
  282. var cameraPos = fromCam.State.RawPosition;
  283. // Special handling for FreeLook: get an undamped outgoing position
  284. if (fromCam is CinemachineNewFreeLook)
  285. {
  286. var orbital = (fromCam as CinemachineNewFreeLook).Transposer;
  287. if (orbital != null)
  288. cameraPos = orbital.GetTargetCameraPosition(worldUp);
  289. }
  290. ForceCameraPosition(cameraPos, fromCam.State.FinalOrientation);
  291. }
  292. }
  293. float GetYAxisClosestValue(Vector3 cameraPos, Vector3 up)
  294. {
  295. if (Follow != null)
  296. {
  297. // Rotate the camera pos to the back
  298. Quaternion q = Quaternion.FromToRotation(up, Vector3.up);
  299. Vector3 dir = q * (cameraPos - Follow.position);
  300. Vector3 flatDir = dir; flatDir.y = 0;
  301. if (!flatDir.AlmostZero())
  302. {
  303. float angle = Vector3.SignedAngle(flatDir, Vector3.back, Vector3.up);
  304. dir = Quaternion.AngleAxis(angle, Vector3.up) * dir;
  305. }
  306. dir.x = 0;
  307. // Sample the spline in a few places, find the 2 closest, and lerp
  308. int i0 = 0, i1 = 0;
  309. float a0 = 0, a1 = 0;
  310. const int NumSamples = 13;
  311. float step = 1f / (NumSamples-1);
  312. for (int i = 0; i < NumSamples; ++i)
  313. {
  314. float a = Vector3.SignedAngle(
  315. dir, GetLocalPositionForCameraFromInput(i * step), Vector3.right);
  316. if (i == 0)
  317. a0 = a1 = a;
  318. else
  319. {
  320. if (Mathf.Abs(a) < Mathf.Abs(a0))
  321. {
  322. a1 = a0;
  323. i1 = i0;
  324. a0 = a;
  325. i0 = i;
  326. }
  327. else if (Mathf.Abs(a) < Mathf.Abs(a1))
  328. {
  329. a1 = a;
  330. i1 = i;
  331. }
  332. }
  333. }
  334. if (Mathf.Sign(a0) == Mathf.Sign(a1))
  335. return i0 * step;
  336. float t = Mathf.Abs(a0) / (Mathf.Abs(a0) + Mathf.Abs(a1));
  337. return Mathf.Lerp(i0 * step, i1 * step, t);
  338. }
  339. return m_VerticalAxis.Value; // stay conservative
  340. }
  341. /// <summary>Internal use only. Called by CinemachineCore at designated update time
  342. /// so the vcam can position itself and track its targets. All 3 child rigs are updated,
  343. /// and a blend calculated, depending on the value of the Y axis.</summary>
  344. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  345. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
  346. override public void InternalUpdateCameraState(Vector3 worldUp, float deltaTime)
  347. {
  348. UpdateTargetCache();
  349. FollowTargetAttachment = 1;
  350. LookAtTargetAttachment = 1;
  351. // Initialize the camera state, in case the game object got moved in the editor
  352. m_State = PullStateFromVirtualCamera(worldUp, ref m_Lens);
  353. m_Rigs[(int)RigID.Top].m_Lens.SnapshotCameraReadOnlyProperties(ref m_Lens);
  354. m_Rigs[(int)RigID.Bottom].m_Lens.SnapshotCameraReadOnlyProperties(ref m_Lens);
  355. // Update our axes
  356. bool activeCam = PreviousStateIsValid || CinemachineCore.Instance.IsLive(this);
  357. if (!activeCam || deltaTime < 0)
  358. m_VerticalAxis.m_Recentering.DoRecentering(ref m_VerticalAxis, -1, 0.5f);
  359. else
  360. {
  361. if (m_VerticalAxis.Update(deltaTime))
  362. m_VerticalAxis.m_Recentering.CancelRecentering();
  363. m_RadialAxis.Update(deltaTime);
  364. m_VerticalAxis.m_Recentering.DoRecentering(ref m_VerticalAxis, deltaTime, 0.5f);
  365. }
  366. // Blend the components
  367. if (mBlender == null)
  368. mBlender = new ComponentBlender(this);
  369. mBlender.Blend(GetVerticalAxisValue());
  370. // Blend the lens
  371. if (m_Rigs[mBlender.OtherRig].m_CustomLens)
  372. m_State.Lens = LensSettings.Lerp(
  373. m_State.Lens, m_Rigs[mBlender.OtherRig].m_Lens, mBlender.BlendAmount);
  374. // Do our stuff
  375. SetReferenceLookAtTargetInState(ref m_State);
  376. InvokeComponentPipeline(ref m_State, worldUp, deltaTime);
  377. ApplyPositionBlendMethod(ref m_State, m_Transitions.m_BlendHint);
  378. // Restore the components
  379. mBlender.Restore();
  380. // Push the raw position back to the game object's transform, so it
  381. // moves along with the camera.
  382. if (Follow != null)
  383. transform.position = State.RawPosition;
  384. if (LookAt != null)
  385. transform.rotation = State.RawOrientation;
  386. // Signal that it's all done
  387. InvokePostPipelineStageCallback(this, CinemachineCore.Stage.Finalize, ref m_State, deltaTime);
  388. PreviousStateIsValid = true;
  389. }
  390. ComponentBlender mBlender;
  391. protected override void OnComponentCacheUpdated()
  392. {
  393. var transposer = Transposer;
  394. if (transposer != null)
  395. {
  396. transposer.HideOffsetInInspector = true;
  397. transposer.m_FollowOffset = new Vector3(
  398. 0, m_Orbits[1].m_Height, -m_Orbits[1].m_Radius);
  399. }
  400. }
  401. private float GetVerticalAxisValue()
  402. {
  403. float range = m_VerticalAxis.m_MaxValue - m_VerticalAxis.m_MinValue;
  404. return (range > UnityVectorExtensions.Epsilon) ? m_VerticalAxis.Value / range : 0.5f;
  405. }
  406. /// <summary>
  407. /// Returns the local position of the camera along the spline used to connect the
  408. /// three camera rigs. Does not take into account the current heading of the
  409. /// camera (or its target)
  410. /// </summary>
  411. /// <param name="t">The t-value for the camera on its spline. Internally clamped to
  412. /// the value [0,1]</param>
  413. /// <returns>The local offset (back + up) of the camera WRT its target based on the
  414. /// supplied t-value</returns>
  415. public Vector3 GetLocalPositionForCameraFromInput(float t)
  416. {
  417. UpdateCachedSpline();
  418. int n = 1;
  419. if (t > 0.5f)
  420. {
  421. t -= 0.5f;
  422. n = 2;
  423. }
  424. Vector3 pos = SplineHelpers.Bezier3(
  425. t * 2f, m_CachedKnots[n], m_CachedCtrl1[n], m_CachedCtrl2[n], m_CachedKnots[n+1]);
  426. pos *= Mathf.Max(0, m_RadialAxis.Value);
  427. return pos;
  428. }
  429. Vector2[] m_CachedOrbits;
  430. float m_CachedTension;
  431. Vector4[] m_CachedKnots;
  432. Vector4[] m_CachedCtrl1;
  433. Vector4[] m_CachedCtrl2;
  434. void UpdateCachedSpline()
  435. {
  436. bool cacheIsValid = (m_CachedOrbits != null && m_CachedTension == m_SplineCurvature);
  437. for (int i = 0; i < 3 && cacheIsValid; ++i)
  438. cacheIsValid = (m_CachedOrbits[i].y == m_Orbits[i].m_Height
  439. && m_CachedOrbits[i].x == m_Orbits[i].m_Radius);
  440. if (!cacheIsValid)
  441. {
  442. float t = m_SplineCurvature;
  443. m_CachedKnots = new Vector4[5];
  444. m_CachedCtrl1 = new Vector4[5];
  445. m_CachedCtrl2 = new Vector4[5];
  446. m_CachedKnots[1] = new Vector4(0, m_Orbits[2].m_Height, -m_Orbits[2].m_Radius, 0);
  447. m_CachedKnots[2] = new Vector4(0, m_Orbits[1].m_Height, -m_Orbits[1].m_Radius, 0);
  448. m_CachedKnots[3] = new Vector4(0, m_Orbits[0].m_Height, -m_Orbits[0].m_Radius, 0);
  449. m_CachedKnots[0] = Vector4.Lerp(m_CachedKnots[0], Vector4.zero, t);
  450. m_CachedKnots[4] = Vector4.Lerp(m_CachedKnots[3], Vector4.zero, t);
  451. SplineHelpers.ComputeSmoothControlPoints(
  452. ref m_CachedKnots, ref m_CachedCtrl1, ref m_CachedCtrl2);
  453. m_CachedOrbits = new Vector2[3];
  454. for (int i = 0; i < 3; ++i)
  455. m_CachedOrbits[i] = new Vector2(m_Orbits[i].m_Radius, m_Orbits[i].m_Height);
  456. m_CachedTension = m_SplineCurvature;
  457. }
  458. }
  459. // Crazy damn thing for blending components at the source level
  460. internal class ComponentBlender
  461. {
  462. Rig.TransposerSettings orbitalSaved = new Rig.TransposerSettings();
  463. Rig.ComposerSettings composerSaved = new Rig.ComposerSettings();
  464. Rig.PerlinNoiseSettings noiseSaved = new Rig.PerlinNoiseSettings();
  465. public int OtherRig;
  466. public float BlendAmount;
  467. CinemachineNewFreeLook mFreeLook;
  468. public ComponentBlender(CinemachineNewFreeLook freeLook) { mFreeLook = freeLook; }
  469. public void Blend(float y)
  470. {
  471. if (y < 0.5f)
  472. {
  473. BlendAmount = 1 - (y * 2);
  474. OtherRig = (int)RigID.Bottom;
  475. }
  476. else
  477. {
  478. BlendAmount = (y - 0.5f) * 2f;
  479. OtherRig = (int)RigID.Top;
  480. }
  481. var orbital = mFreeLook.Transposer;
  482. if (orbital != null && mFreeLook.m_Rigs[OtherRig].m_CustomBody)
  483. {
  484. orbitalSaved.PullFrom(orbital);
  485. mFreeLook.m_Rigs[OtherRig].m_Body.Lerp(orbital, BlendAmount);
  486. }
  487. if (orbital != null)
  488. orbital.m_FollowOffset = mFreeLook.GetLocalPositionForCameraFromInput(y);
  489. var components = mFreeLook.ComponentCache;
  490. var composer = components[(int)CinemachineCore.Stage.Aim] as CinemachineComposer;
  491. if (composer != null && mFreeLook.m_Rigs[OtherRig].m_CustomAim)
  492. {
  493. composerSaved.PullFrom(composer);
  494. mFreeLook.m_Rigs[OtherRig].m_Aim.Lerp(composer, BlendAmount);
  495. }
  496. var noise = components[(int)CinemachineCore.Stage.Noise] as CinemachineBasicMultiChannelPerlin;
  497. if (noise != null && mFreeLook.m_Rigs[OtherRig].m_CustomNoise)
  498. {
  499. noiseSaved.PullFrom(noise);
  500. mFreeLook.m_Rigs[OtherRig].m_Noise.Lerp(noise, BlendAmount);
  501. }
  502. }
  503. public void Restore()
  504. {
  505. var orbital = mFreeLook.Transposer;
  506. if (orbital != null && mFreeLook.m_Rigs[OtherRig].m_CustomBody)
  507. orbitalSaved.PushTo(orbital);
  508. if (orbital != null)
  509. orbital.m_FollowOffset = new Vector3(
  510. 0, mFreeLook.m_Orbits[1].m_Height, -mFreeLook.m_Orbits[1].m_Radius);
  511. var components = mFreeLook.ComponentCache;
  512. var composer = components[(int)CinemachineCore.Stage.Aim] as CinemachineComposer;
  513. if (composer != null && mFreeLook.m_Rigs[OtherRig].m_CustomAim)
  514. composerSaved.PushTo(composer);
  515. var noise = components[(int)CinemachineCore.Stage.Noise] as CinemachineBasicMultiChannelPerlin;
  516. if (noise != null && mFreeLook.m_Rigs[OtherRig].m_CustomNoise)
  517. noiseSaved.PushTo(noise);
  518. }
  519. }
  520. }
  521. }
  522. #endif