Search Unity

Resolved Cinemachine Transposer/Composer at runtime dampen from arbitrary position (Based on X?)

Discussion in 'Cinemachine' started by M4dR0b, Jun 11, 2021.

  1. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    *Usng Cinemachine 2.7.1, Unity 2019.3

    Y-Hello there,

    I'm programmatically adding Follow/LookAt target and Cinemachine Transposer/Composer to a Virtual cam.

    Apparently, based on the X position of the target Transform, the vcam decides whether to dampen its position forward or backward.

    I'm looking for a way to establish a fixed start position, and dampen from there. Blend behavior won't do any good because the camera isn't actually going from one vCam to another.

    I've reproduced a small test vid to show the behavior:



    and here is the script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Cinemachine;
    5. using UnityTemplateProjects;
    6.  
    7. public class TestFocusOnAvatar : MonoBehaviour
    8. {
    9.     public CinemachineVirtualCamera vCam;
    10.     public Vector3 bodyTransposer;
    11.     public Vector3 aimTransposer;
    12.     public Vector3 bodyDamping;
    13.     public List<GameObject> availableAvatars = new List<GameObject>();
    14.  
    15.     private int index;
    16.     private CinemachineTransposer ct;
    17.     private CinemachineComposer cc;
    18.     private CinemachineCollider ext;
    19.     private SimpleCameraController camController;
    20.  
    21.     bool hasExt;
    22.  
    23.     void Start()
    24.     {
    25.         index = 0;
    26.         camController = GetComponent<SimpleCameraController>();
    27.         camController.SetTarget(vCam.transform);
    28.     }
    29.  
    30.     void Update()
    31.     {
    32.         if (Input.GetKeyDown(KeyCode.RightArrow))
    33.             SetFocus(false);
    34.  
    35.         if (Input.GetKeyDown(KeyCode.LeftArrow))
    36.             SetFocus(true);
    37.  
    38.         if (Input.GetKeyDown(KeyCode.K))
    39.             CancelFocus();
    40.     }
    41.  
    42.     public void FocusBtn(int index)
    43.     {
    44.         if (availableAvatars[index].activeInHierarchy)
    45.         {
    46.             vCam.Follow = availableAvatars[index].transform;
    47.             vCam.LookAt = availableAvatars[index].transform;
    48.             SetBodyAndAimComposer();
    49.         }
    50.         Debug.Log($"Index value:{index} - Focusing on {availableAvatars[index].name}");
    51.     }
    52.  
    53.     void SetFocus(bool decrease)
    54.     {
    55.         if (availableAvatars.Count <= 0) return;
    56.         if (!decrease)
    57.             index++;
    58.         else
    59.             index--;
    60.  
    61.         if (index >= availableAvatars.Count)
    62.             index = 0;
    63.  
    64.         if (index < 0)
    65.             index = availableAvatars.Count - 1;
    66.  
    67.         if (availableAvatars[index].activeInHierarchy)
    68.         {
    69.             vCam.Follow = availableAvatars[index].transform;
    70.             vCam.LookAt = availableAvatars[index].transform;
    71.             SetBodyAndAimComposer();
    72.         }
    73.         else
    74.         {
    75.             SetFocus(decrease);
    76.         }
    77.         Debug.Log($"Index value:{index} - Focusing on {availableAvatars[index].name}");
    78.     }
    79.  
    80.     void SetBodyAndAimComposer()
    81.     {
    82.         if (ct == null && cc == null)
    83.         {
    84.             ct = vCam.AddCinemachineComponent<CinemachineTransposer>();
    85.             cc = vCam.AddCinemachineComponent<CinemachineComposer>();
    86.         }
    87.         ct.m_BindingMode = CinemachineTransposer.BindingMode.WorldSpace;
    88.         ct.m_FollowOffset = bodyTransposer;
    89.         ct.m_XDamping = bodyDamping.x;
    90.         ct.m_YDamping = bodyDamping.y;
    91.         ct.m_ZDamping = bodyDamping.z;
    92.  
    93.         cc.m_TrackedObjectOffset = aimTransposer;
    94.         cc.m_VerticalDamping = 0;
    95.         cc.m_HorizontalDamping = 0;
    96.  
    97.         // if (!hasExt)
    98.         // {
    99.         //     ext = (CinemachineCollider)vCam.gameObject.AddComponent(typeof(CinemachineCollider));
    100.         //     hasExt = true;
    101.         // }
    102.     }
    103.  
    104.     public void CancelFocus()
    105.     {
    106.         Debug.LogWarning("Cancelling Focus");
    107.  
    108.         vCam.Follow = null;
    109.         vCam.LookAt = null;
    110.  
    111.         if (ct && cc)
    112.         {
    113.             Destroy(ct);
    114.             ct = null;
    115.             Destroy(cc);
    116.             cc = null;
    117.         }
    118.  
    119.         //Invalidate Pipeline to avoid aving missing component on the virtual camera
    120.         vCam.InvalidateComponentPipeline();
    121.  
    122.         // if (hasExt)
    123.         // {
    124.         //     Destroy(ext);
    125.         //     ext = null;
    126.         //     hasExt = false;
    127.         // }    
    128.     }
    129. }
    Ps: Is Invalidating the pipeline the correct behavior when removing CinemachineComponents? Or there is another way I'm unaware of?

    Thanks :)
     
    Last edited: Jun 11, 2021
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Dynamically adding and removing vcam components is not the recommended way to use Cinemachine. Why don't you make multiple vcams and activate/deactivate them?

    Also, rather than dynamically changing the target, you can adopt this approach: create in invisible game object, and use that as your target. Then, have a custom script on that game object to position itself on top of the item of interest. That way, CM will see its target as moving to a new position, so it will damp its way there. Otherwise, CM will just snap to the new position because it thinks there is a new target.
     
    M4dR0b likes this.
  3. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    Hi Gregoryl,

    Thank you for your time to answer.

    I was afraid I would get this kind of response :D

    The project is a concurrent multicam environment with a virtual console for controlling the cameras simultaneously, I was hoping to get away with something more linear, but I guess I can't get away with what you suggested. The invisible Gameobject is a nice optimization. Thanks!

    Do you think I can reproduce a similar behavior as the video initially posted with custom blending?

    What I'm looking forward is this scenario:

    Camera is free in arbitrary position -> Select a target to focus
    Camera Cut at determined offset from the target -> Camera Ease to it's final position.
    Select another focus -> Camera Cut at determined offset from the target -> Camera Ease to it's final position.

    Thank you :)
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Try cutting to a BlendListCamera, with 2 children:
    1. at determined offset
    2. at the final position
    with a built-in blend between them
     
    Last edited: Jun 20, 2021
    M4dR0b likes this.
  5. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    Thanks, I'll try that