Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We've updated our Terms of Service. Please read our blog post from Unity CTO and Co-Founder Joachim Ante here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Orbital Transposer - Using one binding mode while accessing parameters of another

Discussion in 'Cinemachine' started by caiqueassis, Oct 30, 2018.

  1. caiqueassis


    Oct 13, 2018

    I have been experimenting with Cinemachine for the past few days, trying to make a Third Person camera setup. I got one that works quite well for my purposes so far. Here are the settings:


    I'm currently using the "Simple Follow With World Up" binding mode of the Orbital Transposer, which works wonderfully for my needs. I also implemented a little code to be able to rotate the "X Axis" by pressing certain buttons.

    My problem, however, is that with the "Simple Follow With World Up" binding mode, I don't have access to the "Recenter To Target Heading" setting, and I can't "recenter" the camera with a button press, for instance. I even tried accessing it through code, and while I could set values to it, it wouldn't make any effect if the binding mode was still "Simple Follow With World Up".

    I tried using the "Lock To Target With World Up" binding mode, but it just doesn't work the way I want to. The "Simple Follow With World Up" is already perfect for what I need. I just need to be able to "recenter" the camera behind the Follow Target with the press of a button.

    Is there any possible way of doing that, while still using the "Simple Follow With World Up" binding method? If there isn't, what would be my options to maintain the behaviour of the "Simple Follow With World Up" binding mode, while having a way to "recenter" the camera?

    Thanks in advance.
  2. Gregoryl


    Unity Technologies

    Dec 22, 2016
    The concept of recentering doesn't exist in SimpleFollow because that binding mode is in camera space, in other words it's always centered, because in this mode centered means that camera forward points in the same direction as camera forward.

    It's possible to do what you ask with a CM extension, but it's a little tricky because you have to suppress the Aim damping that would normally occur when the vcam is moved. Here is a sample extension that does the job. Just drop it in your project and add it to the vcam using the Extensions dropdown. The extension assumes that your vcam has a Composer in the Aim. If it has something else, just modify the extension as necessary.

    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3. using Cinemachine.Utility;
    5. public class Recenter : CinemachineExtension
    6. {
    7.     public bool recenter;
    8.     public float recenterTime = 1;
    9.     [Range(1, 4)]
    10.     public float gamma = 1.5f;
    11.     float recenterStartTime;
    13.     class VcamExtraState
    14.     {
    15.         // Change this to the appropriate thing for your vcam
    16.         public CinemachineComposer composer;
    17.         public float savedAimDamping;
    18.     }
    20.     private void OnValidate()
    21.     {
    22.         recenterTime = Mathf.Max(0, recenterTime);
    23.         gamma = Mathf.Max(0, gamma);
    24.     }
    26.     protected override void PostPipelineStageCallback(
    27.         CinemachineVirtualCameraBase vcam,
    28.         CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    29.     {
    30.         if (recenter && stage == CinemachineCore.Stage.Body && vcam.Follow != null)
    31.         {
    32.             // This is needed to suppress the Aim damping.  Modify as necessary
    33.             VcamExtraState extra = GetExtraState<VcamExtraState>(vcam);
    34.             if (extra.composer == null)
    35.             {
    36.                 var vcam2 = vcam as CinemachineVirtualCamera;
    37.                 if (vcam2 != null)
    38.                     extra.composer = vcam2.GetCinemachineComponent<CinemachineComposer>();
    39.             }
    41.             var up = state.ReferenceUp;
    42.             var center = vcam.Follow.position;
    43.             var start = state.RawPosition - center;
    44.             float angle = UnityVectorExtensions.SignedAngle(
    45.                 start.ProjectOntoPlane(up), -vcam.Follow.forward.ProjectOntoPlane(up), up);
    47.             if (recenterStartTime == 0)
    48.                 recenterStartTime = Time.time;
    49.             float t = recenterTime == 0 ? 1 : (Time.time - recenterStartTime) / recenterTime;
    50.             angle = Mathf.Lerp(0, angle, Mathf.Pow(t, gamma));
    52.             var newPos = Quaternion.AngleAxis(angle, up) * start;
    53.             state.RawPosition = center + newPos;
    55.             // Kill the Aim damping
    56.             if (extra.composer != null && extra.composer.m_HorizontalDamping != 0)
    57.             {
    58.                 extra.savedAimDamping = extra.composer.m_HorizontalDamping;
    59.                 extra.composer.m_HorizontalDamping = 0;
    60.             }
    62.             if (t >= 1)
    63.             {
    64.                 recenter = false;
    65.                 recenterStartTime = 0;
    67.                 // Restore the Aim damping
    68.                 if (extra.composer != null)
    69.                     extra.composer.m_HorizontalDamping = extra.savedAimDamping;
    70.             }
    71.         }
    72.     }
    73. }
    caiqueassis likes this.
  3. caiqueassis


    Oct 13, 2018
    This worked wonderfully. It was just what I needed. You sir, saved my life. Thanks a lot!
    Gregoryl likes this.