Recentering keeps bouncing

I would like to have a freelook camera slowly following the player when the player is moving. To do so I implemented the following code:

for (int i = 0; i < m_freelook_cam.Length; i++)
{
      m_freelook_cam[i].m_RecenterToTargetHeading.m_WaitTime = 0.2f;
      m_freelook_cam[i].m_RecenterToTargetHeading.m_RecenteringTime = COMMON_Save.m_instance.GetCurrentSlot().m_cam_repositioning;
      m_freelook_cam[i].m_RecenterToTargetHeading.m_enabled = Mathf.Abs(COMMON_Gamepad.m_instance.m_left_axis_magnitude) > 0.1f;

}

Unfortunately as shown in this video the camera keeps bouncing and never moving behind the character:

I have also try moving the camera directly but the same issue happens:

float l_angle = COMMON_MathHelper.SignedVectorAngle(Vector3.forward, Vector3.ProjectOnPlane(m_target.forward, Vector3.up), Vector3.up);

for (int i = 0; i < m_freelook_cam.Length; i++)
{
      if (Mathf.Abs(COMMON_Gamepad.m_instance.m_left_axis_magnitude) > 0.1f)
      {
           m_freelook_cam[i].m_XAxis.Value = Mathf.Lerp(m_freelook_cam[i].m_XAxis.Value, l_angle, Time.deltaTime * COMMON_Save.m_instance.GetCurrentSlot().m_cam_repositioning);
           m_freelook_cam[i].m_YAxis.Value = Mathf.Lerp(m_freelook_cam[i].m_YAxis.Value, 0.5f, Time.deltaTime * COMMON_Save.m_instance.GetCurrentSlot().m_cam_repositioning);
      }
               
}

I’m using this exact same code when I want to recenter the camera inmediately (without the Lerp) and there it works fine with no issues.

I’m using a statedriven cam and I also noticed (you can see in the video around the 30s mark) that when the statedriven camera changes to another freelook it seems to somewhow bump the recenteting speed for a bit.

Here is a screenshot of the freelook camera component:

Have you tried changing the binding mode to SimpleFollowWithWorldUp? I think that will give you a nice naturalistic recentering when the target is moving.

The downside is that you’ll lose the FreeLook’s built-in recentering feature, and your custom recentering code will be a little more complicated. This is because in SimpleFollow, the Axis values are in camera-relative co-ordinates, so that that an X axis value of 0 means “where the camera is”. But all is not lost. Here is a sample script to recenter a SimpleFollow camera to be behind the player.

using UnityEngine;
using Cinemachine;
using Cinemachine.Utility;

public class SimpleFollowRecenter : CinemachineExtension
{
    public bool Recenter;
    public float RecenterTime = 0.5f;

    protected override void PostPipelineStageCallback(
        CinemachineVirtualCameraBase vcam,
        CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    {
        if (stage != CinemachineCore.Stage.Body)
            return;

        Transform target = vcam != null ? vcam.Follow : null;
        if (target == null)
            return;

        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) < 0.1f)
                Recenter = false; // done!
            else
            {
                angle = Damper.Damp(angle, RecenterTime, deltaTime);
                Vector3 pos = state.RawPosition - target.position;
                pos = Quaternion.AngleAxis(angle, up) * pos;
                state.RawPosition = pos + target.position;
            }
        }
    }
}
2 Likes

Hey @Gregoryl thanks so much for the help!

I didn’t know SimpleFollowWithWorldUp will do that automacally. Is there an option to adjust how fast is trying to move behind the back?

Thanks!

There is no active recentering in simple follow. As the target moves forward, the camera is passively dragged along behind it, like a wheelbarrow being pulled. The motion gives a very natural follow. If you want to actively recenter, then you have to use the custom script I gave, or some modified version of it.

Perfect, thanks!