Trouble Recentering The X Axis of the Free look Camera

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.

1 Like

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.

5 Likes

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!

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?

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.

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.

using UnityEngine;
using Cinemachine;
using Cinemachine.Utility;
public class SimpleFollowRecenter : MonoBehaviour
{
    public bool recenter;
    public float recenterTime = 0.5f;
    CinemachineFreeLook vcam;
    CinemachineOrbitalTransposer[] orbital = new CinemachineOrbitalTransposer[3];
    CinemachineVirtualCamera[] rigs = new CinemachineVirtualCamera[3];

    void Start()
    {
        vcam = GetComponent<CinemachineFreeLook>();
        for (int i = 0; vcam != null && i < 3; ++i)
        {
            rigs[i] = vcam.GetRig(i);
            orbital[i] = rigs[i].GetCinemachineComponent<CinemachineOrbitalTransposer>();
        }
    }
 
    void Update()
    {
        Transform target = vcam != null ? vcam.Follow : null;
        if (target == null)
            return;

        // Disable the transposers while recentering
        for (int i = 0; i < 3; ++i)
            orbital[i].enabled = !recenter;

        if (recenter)
        {
            // How far away from centered are we?
            Vector3 up = vcam.State.ReferenceUp;
            Vector3 back = vcam.transform.position - target.position;
            float angle = UnityVectorExtensions.SignedAngle(
                back.ProjectOntoPlane(up), -target.forward.ProjectOntoPlane(up), up);
            if (Mathf.Abs(angle) < UnityVectorExtensions.Epsilon)
                recenter = false; // done!

            // Do the recentering on all 3 rigs
            angle = Damper.Damp(angle, recenterTime, Time.deltaTime);
            for (int i = 0; recenter && i < 3; ++i)
            {
                Vector3 pos = rigs[i].transform.position - target.position;
                pos = Quaternion.AngleAxis(angle, up) * pos;
                rigs[i].transform.position = pos + target.position;
            }
        }
    }
}

For the second edge case, open the FreeLook’s “Transitions” section in the inspector and put these settings:

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

Let me know if these solutions work out for you.

4 Likes

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:


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:

```csharp
void setFollowingCamForward (Vector3 forward, UnityAction onChangeActive = null)
{
        forward.Normalize ();

        CinemachineFreeLook followCam = m_minion.FollowCam;

        Vector3 targetPos = followCam.Follow.position;

        Vector3 camForward = targetPos - followCam.transform.position;

        // Set forward on all 3 rigs
        for (int i = 0; i < 3; ++i)
        {
                followCam.GetRig (i).GetCinemachineComponent<CinemachineOrbitalTransposer> ().enabled = false;

                Vector3 pos = followCam.GetRig (i).transform.position - targetPos;
                pos = Quaternion.AngleAxis(angle, Vector3.up) * pos;

                Vector3 newPos = targetPos - forward * followCam.m_Orbits[i].m_Radius +
                        Vector3.up * followCam.m_Orbits[i].m_Height;

                followCam.GetRig (i).transform.position = newPos;
        }

        StartCoroutine (enableOrbitals (onChangeActive));
}

IEnumerator enableOrbitals (UnityAction onChangeActive = null)
{
        yield return null;

        CinemachineFreeLook followCam = m_minion.FollowCam;

        for (int i = 0; i < 3; ++i)
        {
                followCam.GetRig (i).GetCinemachineComponent<CinemachineOrbitalTransposer> ().enabled = true;
        }

        yield return null;

        if (onChangeActive != null)
        {
                onChangeActive ();
        }
}

Once again, thank you very much for your help Gregoryl!

2 Likes

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.

Same trouble here, I have a similar thread , see #3 .

EDIT: Solved!

if (_updateYAxis)
            if (_cm_freeLook.m_YAxis.Value > yAxisRecenterValue) {
                _cm_freeLook.m_YAxis.Value -= yAxisRecenterSpeed *
                                              (Time.deltaTime / _cm_freeLook.m_RecenterToTargetHeading.m_RecenteringTime);
                if (_cm_freeLook.m_YAxis.Value <= yAxisRecenterValue)
                    StopRecenterYAxis();
            } else if (_cm_freeLook.m_YAxis.Value < yAxisRecenterValue) {
                _cm_freeLook.m_YAxis.Value += yAxisRecenterSpeed *
                                              (Time.deltaTime / _cm_freeLook.m_RecenterToTargetHeading.m_RecenteringTime);
                if (_cm_freeLook.m_YAxis.Value >= yAxisRecenterValue)
                    StopRecenterYAxis();
            }
1 Like

Just use the built-in Y-axis recentering function, it works even in SimpleFollow mode:

4008001--345913--upload_2018-12-17_12-56-18.png

i searched it 4-5 time yet i did not any option called as “Y axis recentering”

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).

brother but package manager shows me i am upto date. i am using 2.2.8 version of cinemachine

posted a image above

Use binding mode as World Space

bang… found it . i just uninstall cinemachine and install it again. and found the option of y center :slight_smile: thanks

@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! :slight_smile:

4011115--346318--1.png

1 Like

brother do you know any way

:slight_smile: yup by the way brother do you know any way to change the deadzone of freelook camera by script?

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.

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.