Search Unity

Trouble Recentering The X Axis of the Free look Camera

Discussion in 'Cinemachine' started by bagle45, Jul 5, 2018.

  1. bagle45

    bagle45

    Joined:
    Jul 25, 2016
    Posts:
    17
    Hi,
    We've been Integrating Cinemachine into our party game, and I'm really impressed with the feature set so far, especially the free-look camera.

    We've hit a bit of a roadblock however, with how to recenter the camera on the X Axis. I've tried setting
    m_RecenterToTargetHeading.m_enabled to true, as well as m_XAxis.DoRecentering(), without any result. By Contrast, the Y Axis recentering works as expected.

    Furthermore, I'm curious as to where the state of the X Axis is stored in the free-look camera. The "Value" of the X Axis is always 0, and setting it to anything other than 0 effects a small rotation before it returns to 0. Does the value you enter here correspond to a rotation of "Value "Degrees in the X axis?

    We've tried Cinemachine Versions 2.1.10 & 2.2 with Unity versions 2017.4 & 2018.1. We can reproduce this in a fresh 2018.1 project using the "Freelook character" Cinemachine example scene.

    Thank you.
     
    Patrick_Machado_ likes this.
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,721
    This is probably because you have the Binding Mode set to Simple Follow with World Up. This is a camera-space binding mode, meaning that the "reset" position is always in the direction that the camera is pointing - so it's always centered, which is why the axis Value is always 0. Try changing the binding mode to something else, like Target with World Up. Binding Mode defines the context in which the Axis Value is interpreted.
     
  3. bagle45

    bagle45

    Joined:
    Jul 25, 2016
    Posts:
    17
    Hi Gregoryl, Thanks for the info, that explains quite a lot.

    I'm afraid I don't see a binding mode like this. I see a number of "lock to target" options, and a "world space" option, which makes the camera behave like the "Z-Targeting" mode form the Legend of Zelda games.

    I thought maybe I could effect what I was after by swapping between binding modes, performing the recenter, and then swapping back to Simple Follow, but the camera keeps snapping back to it's original rotation the moment I swap the binding mode back to Simple Follow, regardless of the values I assign to to the X axis before doing so.

    Thanks again for your help!
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,721
    You should be able to get what you want without swapping anything around.
    My problem: I don't really understand what you want. Can you describe the sorts of movements the player will be doing, and how you'd like the camera to respond?
     
  5. bagle45

    bagle45

    Joined:
    Jul 25, 2016
    Posts:
    17
    The game is a third person shooter similar to splatoon, so the character will be running & jumping like most 3rd person shooters/platformers. The "Simple Follow with World Up" Camera behaves exactly how we want the camera to behave. I'm just looking for a way to handle two edge cases:
    1) recenter the camera behind the player (Preferably with a quick rotation around the player to get there) when a "Recenter" button is pressed.
    2) When transitioning from another camera to this one, have the free look camera rotation start with the same rotation as the camera it just transitioned from.
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,721
    Well, the concept of "centered" doesn't really exist for the SimpleFollow binding mode. However, it is possible to write a script to recenter it, according to the script's own definition of centered. Here is one that rotates the FreeLook to be behind the target. Just add it to the FreeLook.
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3. using Cinemachine.Utility;
    4. public class SimpleFollowRecenter : MonoBehaviour
    5. {
    6.     public bool recenter;
    7.     public float recenterTime = 0.5f;
    8.     CinemachineFreeLook vcam;
    9.     CinemachineOrbitalTransposer[] orbital = new CinemachineOrbitalTransposer[3];
    10.     CinemachineVirtualCamera[] rigs = new CinemachineVirtualCamera[3];
    11.  
    12.     void Start()
    13.     {
    14.         vcam = GetComponent<CinemachineFreeLook>();
    15.         for (int i = 0; vcam != null && i < 3; ++i)
    16.         {
    17.             rigs[i] = vcam.GetRig(i);
    18.             orbital[i] = rigs[i].GetCinemachineComponent<CinemachineOrbitalTransposer>();
    19.         }
    20.     }
    21.  
    22.     void Update()
    23.     {
    24.         Transform target = vcam != null ? vcam.Follow : null;
    25.         if (target == null)
    26.             return;
    27.  
    28.         // Disable the transposers while recentering
    29.         for (int i = 0; i < 3; ++i)
    30.             orbital[i].enabled = !recenter;
    31.  
    32.         if (recenter)
    33.         {
    34.             // How far away from centered are we?
    35.             Vector3 up = vcam.State.ReferenceUp;
    36.             Vector3 back = vcam.transform.position - target.position;
    37.             float angle = UnityVectorExtensions.SignedAngle(
    38.                 back.ProjectOntoPlane(up), -target.forward.ProjectOntoPlane(up), up);
    39.             if (Mathf.Abs(angle) < UnityVectorExtensions.Epsilon)
    40.                 recenter = false; // done!
    41.  
    42.             // Do the recentering on all 3 rigs
    43.             angle = Damper.Damp(angle, recenterTime, Time.deltaTime);
    44.             for (int i = 0; recenter && i < 3; ++i)
    45.             {
    46.                 Vector3 pos = rigs[i].transform.position - target.position;
    47.                 pos = Quaternion.AngleAxis(angle, up) * pos;
    48.                 rigs[i].transform.position = pos + target.position;
    49.             }
    50.         }
    51.     }
    52. }
    For the second edge case, open the FreeLook's "Transitions" section in the inspector and put these settings:

    upload_2018-7-7_8-31-11.png

    Let me know if these solutions work out for you.
     
    Last edited: Jul 7, 2018
  7. bagle45

    bagle45

    Joined:
    Jul 25, 2016
    Posts:
    17
    Wow, that script is exactly what I needed, thank you so much Gregoryl! Really appreciate it!
    I made just a few small tweaks to it. It takes a quite a while for the damp function to reach epsilon, so I put a much larger number in there instead. It also causes a null reference exception in the free-look camera's inspector (line 163), but a simple null check fixed that:
    Quaternion orient = MiddleRig.GetReferenceOrientation (up); 

    Became:
    Quaternion orient = Quaternion.identity;

    if (MiddleRig)
    orient = MiddleRig.GetReferenceOrientation (up);


    I tried using blend hints as you suggested, and they're quite nice. I was just having a little difficulty getting them to behave when using instantiated prefabs containing the virtual cameras. They seemed to just be ignored it most cases.
    Part way through testing things though, I realized that the blend hints weren't quite what I was looking for in any case. I wanted to have a bit more control over how the Free look framed what the previous camera what just looking at, and so, with the insight your wonderful code gave me, I came up with the following:
    Code (CSharp):
    1. void setFollowingCamForward (Vector3 forward, UnityAction onChangeActive = null)
    2. {
    3.         forward.Normalize ();
    4.  
    5.         CinemachineFreeLook followCam = m_minion.FollowCam;
    6.  
    7.         Vector3 targetPos = followCam.Follow.position;
    8.  
    9.         Vector3 camForward = targetPos - followCam.transform.position;
    10.  
    11.         // Set forward on all 3 rigs
    12.         for (int i = 0; i < 3; ++i)
    13.         {
    14.                 followCam.GetRig (i).GetCinemachineComponent<CinemachineOrbitalTransposer> ().enabled = false;
    15.  
    16.                 Vector3 pos = followCam.GetRig (i).transform.position - targetPos;
    17.                 pos = Quaternion.AngleAxis(angle, Vector3.up) * pos;
    18.  
    19.                 Vector3 newPos = targetPos - forward * followCam.m_Orbits[i].m_Radius +
    20.                         Vector3.up * followCam.m_Orbits[i].m_Height;
    21.  
    22.                 followCam.GetRig (i).transform.position = newPos;
    23.         }
    24.  
    25.         StartCoroutine (enableOrbitals (onChangeActive));
    26. }
    27.  
    28. IEnumerator enableOrbitals (UnityAction onChangeActive = null)
    29. {
    30.         yield return null;
    31.  
    32.         CinemachineFreeLook followCam = m_minion.FollowCam;
    33.  
    34.         for (int i = 0; i < 3; ++i)
    35.         {
    36.                 followCam.GetRig (i).GetCinemachineComponent<CinemachineOrbitalTransposer> ().enabled = true;
    37.         }
    38.  
    39.         yield return null;
    40.  
    41.         if (onChangeActive != null)
    42.         {
    43.                 onChangeActive ();
    44.         }
    45. }
    Once again, thank you very much for your help Gregoryl!
     
    Last edited: Jul 9, 2018
    Patrick_Machado_ and Gregoryl like this.
  8. Imamul125

    Imamul125

    Joined:
    Oct 5, 2018
    Posts:
    14
    any way to Recenter Axis-y . as i am new i am find it hard to understand this code. my x gets recenter but i want y also to be recenter.
     
  9. IEdge

    IEdge

    Joined:
    Mar 25, 2017
    Posts:
    51
    Same trouble here, I have a similar thread, see #3.

    EDIT: Solved!
    Code (CSharp):
    1. if (_updateYAxis)
    2.             if (_cm_freeLook.m_YAxis.Value > yAxisRecenterValue) {
    3.                 _cm_freeLook.m_YAxis.Value -= yAxisRecenterSpeed *
    4.                                               (Time.deltaTime / _cm_freeLook.m_RecenterToTargetHeading.m_RecenteringTime);
    5.                 if (_cm_freeLook.m_YAxis.Value <= yAxisRecenterValue)
    6.                     StopRecenterYAxis();
    7.             } else if (_cm_freeLook.m_YAxis.Value < yAxisRecenterValue) {
    8.                 _cm_freeLook.m_YAxis.Value += yAxisRecenterSpeed *
    9.                                               (Time.deltaTime / _cm_freeLook.m_RecenterToTargetHeading.m_RecenteringTime);
    10.                 if (_cm_freeLook.m_YAxis.Value >= yAxisRecenterValue)
    11.                     StopRecenterYAxis();
    12.             }
     
    Last edited: Dec 17, 2018
    Patrick_Machado_ likes this.
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,721
    Just use the built-in Y-axis recentering function, it works even in SimpleFollow mode:

    upload_2018-12-17_12-56-18.png
     
  11. Imamul125

    Imamul125

    Joined:
    Oct 5, 2018
    Posts:
    14
    i searched it 4-5 time yet i did not any option called as "Y axis recentering"
    Screenshot (929).png


    Screenshot (930).png
     
  12. IEdge

    IEdge

    Joined:
    Mar 25, 2017
    Posts:
    51
    Maybe is because you are using CM from the asset store or have a old version. What you have to do is delete CM and CMExamples folders and reinstall it from the package manager (or update if you already have as package manager).
     
  13. Imamul125

    Imamul125

    Joined:
    Oct 5, 2018
    Posts:
    14
    brother but package manager shows me i am upto date. i am using 2.2.8 version of cinemachine
     
  14. Imamul125

    Imamul125

    Joined:
    Oct 5, 2018
    Posts:
    14
    posted a image above
     
  15. IEdge

    IEdge

    Joined:
    Mar 25, 2017
    Posts:
    51
    Use binding mode as World Space
     
  16. Imamul125

    Imamul125

    Joined:
    Oct 5, 2018
    Posts:
    14
    bang.. found it . i just uninstall cinemachine and install it again. and found the option of y center :) thanks
     
  17. IEdge

    IEdge

    Joined:
    Mar 25, 2017
    Posts:
    51
    @Imamul125 In my inspector:



    Looks different, are you sure that you are using CinemachineExamples folder up to date? Reimport examples from the Cinemachine menu should solve the problem.

    EDIT: Oh! I read your above answer just 1 min later! haha I'm glad you solved it! :)
     

    Attached Files:

    • 1.png
      1.png
      File size:
      25.7 KB
      Views:
      8,092
    Imamul125 likes this.
  18. Imamul125

    Imamul125

    Joined:
    Oct 5, 2018
    Posts:
    14
    brother do you know any way
    :) yup by the way brother do you know any way to change the deadzone of freelook camera by script?
     
  19. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,721
    Look in ScriptingExample.cs that you'll find in CinemachineExamples. Inside the Start() method it's setting some FreeLook fields by script. That should get you going.
     
  20. FGRivera

    FGRivera

    Joined:
    Jun 3, 2013
    Posts:
    16
    Hi there. I've been using this solution for my project and its worked out great, but recently needed to upgrade Unity versions. Now CM 2.9,7, this recentering script doesn't work unless the camera has utilized the top or bottom rig. Once it has done so it works as expected, even back on the middle rig.
     
    Last edited: Jun 19, 2023
  21. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,721
    This is a very old thread, and there is more than one script here. Can you make a little sample project that includes your recentering code, to show the problem?
     
  22. neviovalsa

    neviovalsa

    Joined:
    Jun 24, 2019
    Posts:
    52
    I know it's an old post, but I found a quick solution that might help people using Simple Follow with World Up.

    I simply wrote a coroutine that temporarily switches to Lock To Target With World Up, enables recentering for it's duration and switches back to Simple Follow with World Up.

    Code (CSharp):
    1. /// <summary>
    2.         /// Repositions the camera behind it's target, facing the target's forward direction
    3.         /// </summary>
    4.         /// <returns></returns>
    5.         private IEnumerator RecenterFreeLookCamera(CinemachineFreeLook _thirdPersonCamera)
    6.         {
    7.             var previousBindingMode = _thirdPersonCamera.m_BindingMode;
    8.             _thirdPersonCamera.m_BindingMode = CinemachineTransposer.BindingMode.LockToTargetWithWorldUp;
    9.             _thirdPersonCamera.m_RecenterToTargetHeading.m_enabled = true;
    10.             yield return new WaitForSeconds(_thirdPersonCamera.m_RecenterToTargetHeading.m_RecenteringTime + _thirdPersonCamera.m_RecenterToTargetHeading.m_WaitTime);
    11.             _thirdPersonCamera.m_RecenterToTargetHeading.m_enabled = false;
    12.             _thirdPersonCamera.m_BindingMode = previousBindingMode;
    13.         }
    If you don't want to use a Coroutine you can do the following, but you lose the smooth transition provided by Cinemachine

    Code (CSharp):
    1. private void ResetCameraBehindPlayer()
    2.         {
    3.             var previousBindingMode = _thirdPersonCamera.m_BindingMode;
    4.             _thirdPersonCamera.m_BindingMode = CinemachineTransposer.BindingMode.LockToTargetWithWorldUp;
    5.             _thirdPersonCamera.m_YAxis.Value = 0.5f;
    6.             _thirdPersonCamera.m_XAxis.Value = 0f;
    7.             _thirdPersonCamera.m_BindingMode = previousBindingMode;
    8.         }