Search Unity

Question When too close to LookAt target using composer, the camera will spin indefinitely

Discussion in 'Cinemachine' started by hungleuk_chan, Jan 7, 2023.

  1. hungleuk_chan

    hungleuk_chan

    Joined:
    Apr 24, 2020
    Posts:
    1
    I am creating a souls-like lock on system.

    I am using a Framing transposer + composer to create the desire effect. It works great when the target is far away, but when the target is too close or below the Follow game object, the camera behaves weirdly.

    First, the camera will slowly tilted until it look straight down at the target, after that it will spin in really high speed. Why is that? Is there a way to solve this?

    upload_2023-1-7_23-29-54.png
    upload_2023-1-7_23-30-9.png
    upload_2023-1-7_23-30-33.png
     
  2. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    That's the expected behaviour. Your camera is following the blue guy and looking at the red guy. When the red guy moves close, the camera may tilt up or down depending on the targets relative position. When that happens framing transposer repositions the camera to match this rotation.

    If the follow and lookat targets are at the same height, then this won't happen. So adjust the Character's and LockOnTarget's y position, so they are at the same height.


    You can also try the setup described in this post:
    https://forum.unity.com/threads/target-lock-on-camera-issues.1350320/#post-8530517
    This won't have the above problem even when the targets have different heights.
     
  3. EricChan

    EricChan

    Joined:
    Jul 14, 2014
    Posts:
    8
    Thanks for the explanation. I have tried your suggestion; the same behavior is observed even they have the same height with no tracked offset.

    I have tried the 3rd person camera approach, but sadly it cannot create the same effect as the Framing Transposer. The blue character will move away from the camera (closer to the center of the screen) and having problem to look down at a target below the character.

    From what I observed in Elden ring / Dark souls. Their lock on won't drift when the enemy is too close or below the player, I can also observe they have applied some clamping to avoid look straight down /up.

    Is there a way to add a clamp to the tilt angle just like the top rig radius settings of a FreeLook camera?
     
  4. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    I could not reproduce the problem in this case.

    Could you show a recording where the effect is different?

    Yes, you could write a CinemachineExtension. The extension should limit state.RawOrientation between some values; to only limit the tilt angle you would clamp
    state.RawOrientation.eulerAngles.x between some values (e.g. -20, 20).
    Take CinemachineCameraOffset.cs as an example. Let me know if you need help modifying it.
     
  5. EricChan

    EricChan

    Joined:
    Jul 14, 2014
    Posts:
    8
    After adding the clamping, it works as I imagined.
    Thanks for the help @gaborkb !

    Here is the result


    For anyone who is interested in the clamping, here is the script:

    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;  
    3.  
    4. public class LockOnCameraClamp : CinemachineExtension
    5. {
    6.     public float minAngle = -20;
    7.     public float maxAngle = 20;
    8.  
    9.     /// <summary>
    10.     /// When to apply the offset
    11.     /// </summary>
    12.     [Tooltip("When to apply the offset")]
    13.     public CinemachineCore.Stage m_ApplyAfter = CinemachineCore.Stage.Aim;
    14.  
    15.  
    16.     /// <summary>
    17.     /// Applies the specified offset to the camera state
    18.     /// </summary>
    19.     /// <param name="vcam">The virtual camera being processed</param>
    20.     /// <param name="stage">The current pipeline stage</param>
    21.     /// <param name="state">The current virtual camera state</param>
    22.     /// <param name="deltaTime">The current applicable deltaTime</param>
    23.     protected override void PostPipelineStageCallback(
    24.         CinemachineVirtualCameraBase vcam,
    25.         CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    26.     {
    27.         if (stage == m_ApplyAfter)
    28.         {
    29.             var newX = ClampAngle(state.RawOrientation.eulerAngles.x, minAngle, maxAngle);
    30.             var newEuler = new Vector3(newX, state.RawOrientation.eulerAngles.y, state.RawOrientation.eulerAngles.z);
    31.             state.RawOrientation.eulerAngles = newEuler;
    32.         }
    33.     }
    34.  
    35.     private static float ClampAngle(float current, float min, float max)
    36.     {
    37.         float dtAngle = Mathf.Abs(((min - max) + 180) % 360 - 180);
    38.         float hdtAngle = dtAngle * 0.5f;
    39.         float midAngle = min + hdtAngle;
    40.         float offset = Mathf.Abs(Mathf.DeltaAngle(current, midAngle)) - hdtAngle;
    41.         if (offset > 0)
    42.         {
    43.             current = Mathf.MoveTowardsAngle(current, midAngle, offset);
    44.         }
    45.  
    46.         return current;
    47.     }
    48. }