Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Resolved Looking at two objects in line

Discussion in 'Cinemachine' started by aselecky, May 25, 2020.

  1. aselecky

    aselecky

    Joined:
    Jul 12, 2017
    Posts:
    3
    Hi guys. I'm working on camera system for our game, and I ran into a problem. I'm trying to persuade Cinemachine Virtual Camera to look at one object "through" another - align their horizontal screen position.
    Example:

    I'm tracking moving object A, and want to keep looking at both objects at the same time, at the same position. I tried using CM Target Group, but this just creates virtual point in space, so if the camera is at wrong position, it just rotates toward that point, many times not event looking at any of the objects. I wrote simple script that rotated camera in a way that it looked fairly okay-ish, it executed in LateUpdate before CMBrain, but it stopped working, I probably changed some setting which is blocking correct execution of rotation. However, my question is if it is even possible to do using CM components, or should I try to fix my script, or rewrite it as CM extension.

    Thanks for any help!

    [Using Unity 2018.4.22f1 and CM 2.5.0]

    Code (CSharp):
    1. private void Update()
    2. {
    3.     Vector3    difference = objectB.position - _tr.position;
    4.     Quaternion rotation   = Quaternion.LookRotation(difference, Vector3.up);
    5.     _goalRotation = rotation;
    6. }
    7.  
    8. void LateUpdate()
    9. {
    10.     _lastRotation = Quaternion.Slerp(_lastRotation, _goalRotation, power * Time.deltaTime);
    11.     _lastRotation = _goalRotation;
    12.     _oldRot = _tr.localRotation.eulerAngles;
    13.     _tr.rotation = _lastRotation;
    14.     _newRot = _tr.localRotation.eulerAngles;
    15.     _newRot.x = _oldRot.x;
    16.     _tr.rotation = Quaternion.Euler(_newRot);
    17. }

    Edit: Just for clarity, script was used on CM Virtual Camera, with Follow and Look At set to object A, and it was rotating to see object B.
     
    Last edited: May 25, 2020
  2. aselecky

    aselecky

    Joined:
    Jul 12, 2017
    Posts:
    3
    Okay, so apparently setting Follow to object A, Look At to B, follow offset to zero, and then using CM Camera Offset extension does exactly what I had in mind. Maybe this will help someone in the future :)
     
    Gregoryl and gaborkb like this.
  3. aselecky

    aselecky

    Joined:
    Jul 12, 2017
    Posts:
    3
    Hey, it's me again! So, my solution worked great, up until I tried to blend into that VCam. It was all over place in transition half of the time, moved weirdly and desired objects weren't even in frame, up until the transition stopped. This problem was more prominent when objects were close, or very distant. I tried to tinker with parameters for the most part of the week, but nothing helped, many settings broke transitions even more. So I had to hack together custom extension.
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. [AddComponentMenu("")] // Hide in menu
    5. [SaveDuringPlay]
    6. #if UNITY_2018_3_OR_NEWER
    7. [ExecuteAlways]
    8. #else
    9. [ExecuteInEditMode]
    10. #endif
    11. public class CinemachineCustomLookAt : CinemachineExtension
    12. {
    13.     public Transform secondLookAt;
    14.     public float followOffset = 10.0f;
    15.     [Range(0.0f, 1.0f)]
    16.     public float lookSpeed = 0.1f;
    17.  
    18.     private Transform _tr;
    19.  
    20.     private float _currentAngle = 0.0f;
    21.     private Vector3 _positionOffset = Vector3.zero;
    22.  
    23.     private Vector3 _diff1;
    24.     private Vector3 _diff2;
    25.     private float _angleDifference;
    26.     private float _minAngle = 0.001f;
    27.  
    28.     private float _dampVelocity = 0.0f;
    29.     private bool _canProcess = false;
    30.  
    31.     public Transform SecondLookAt   // Use this when setting from code
    32.     {
    33.         get => secondLookAt;
    34.         set
    35.         {
    36.             secondLookAt = value;
    37.             GetAndCheckObjects();
    38.         }
    39.     }
    40.  
    41.     private void OnValidate()
    42.     {
    43.         GetAndCheckObjects();
    44.     }
    45.  
    46.     private void GetAndCheckObjects()
    47.     {
    48.         _tr = gameObject.transform;
    49.         _canProcess = SecondLookAt != null;
    50.     }
    51.  
    52.     protected override void PostPipelineStageCallback(
    53.     CinemachineVirtualCameraBase vcam,
    54.     CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    55.     {
    56.         if (stage == CinemachineCore.Stage.Body)
    57.         {
    58.             if (_canProcess)
    59.             {
    60.                 _positionOffset.x = followOffset * Mathf.Cos(_currentAngle);
    61.                 _positionOffset.z = followOffset * Mathf.Sin(_currentAngle);
    62.                 state.PositionCorrection += _positionOffset;
    63.  
    64.                 _diff1 = SecondLookAt.position - vcam.LookAt.position;
    65.                 _diff2 = _positionOffset;
    66.                 _diff1.y = _diff2.y = 0;
    67.                 _angleDifference = Vector3.SignedAngle(_diff1, -_diff2, Vector3.up) / Mathf.PI;
    68.  
    69.                 if (Mathf.Abs(_angleDifference) > _minAngle)
    70.                     _currentAngle = Mathf.Lerp(_currentAngle, _currentAngle + _angleDifference, Time.deltaTime * lookSpeed);
    71.             }
    72.         }
    73.     }
    74. }

    Extension does two things, it calculates position on circle around object A using _currentAngle based on given followOffset. Then it looks at three objects (VCam, A and B), calculates angle between them and tries to minimize it by changing _currentAngle over time. If someone would want to try it, you will need to set your Follow and Look At transforms to object A, your Follow Offset in Body of your VCam to 0, then change the offset in extension. Set your Second Look At in extension to object B and you are all set! Almost. Because of the nature of cameras in general you could get to point, where all objects are perfectly aligned, but offcenter. I fixed it by playing with Aim of VCam, mainly setting Horizontal Damping and Lookahead Time to 0, it helped and now all objects are always centered. Hope this will help someone!
     
unityunity