Search Unity

Set Rotation of Cinemachine Freelook Camera

Discussion in 'Cinemachine' started by rocksquarethunder, Jun 18, 2020.

  1. rocksquarethunder

    rocksquarethunder

    Joined:
    Mar 4, 2020
    Posts:
    7
    Hi!

    I'm using Cinemachine Freelook Camera and it works nice, but at some points in the game I want to set rotation of the camera from code. How can I do that? I couldn't find any method that does that.
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    You can't really do that, because the FreeLook would immediately re-orient the camera based on its procedural algorithm to track the target. That said, there very probably are ways to get what you need. Can you describe the bahviour you're looking for? You set the camera rotation. How are you setting it in relation to the LookAt/Follow target? Where was the camera before? How should the camera behave after you set the rotation?
     
  3. rocksquarethunder

    rocksquarethunder

    Joined:
    Mar 4, 2020
    Posts:
    7
    Thanks for a quick answer! I want to keep LookAt and Follow as is, so still looking at my player. I just want to change the angle the camera is looking from, just like if player would rotate it manually using gamepad. I know I can create another virtual camera and blend to it, which is an ok solution, but require too much setup for easy situations, e.g. Player is entering the lift. He's gonna move down on this lift, but this means that camera will go into wall on one side. So I want to do a tiny cutscene where I change the camera angle, then when I release player's controls I want him the Camera to start in this angle I set, not go back to an angle he had when he entered the lift. Of course he can move his camera as before, but at least he got this "suggested" angle that is not blocked by obstacles.

    Another thing that could fix this and other problems is if I could make Collider Extension work by only changing angles, becuase right now it goes into walls and close to the player instead of just rotating to find a nice angle.
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    You could certainly write a custom extension to find a nice angle and rotate there (might confuse the player, though. Imagine if your car could ignore the steering wheel input whenever it felt like it and go its own way...)

    However, if you know a good angle for the FreeLook in the elevator situation, you can have a script that directly modifies FreeLook.m_XAxis.Value. That will rotate the camera as you describe.
     
  5. rocksquarethunder

    rocksquarethunder

    Joined:
    Mar 4, 2020
    Posts:
    7
    It looks like it might be it, but one more thing - if I set m_XAxis.Value to 90 is it change angle by 90 or set angle as 90?
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Depends on the binding mode. What is the freeLook's binding mode?
     
  7. rocksquarethunder

    rocksquarethunder

    Joined:
    Mar 4, 2020
    Posts:
    7
    Simple Follow With World Up. Although now I've tested WorldSpace, and it seems to be working the same, just reacting differently to setting the axis
     
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Exactly. SimpleFollow is in camera space (Value is in degrees relative to camera forward), so axis value is always 0 (camera can't be looking where it's not looking). If you set it to 90, camera will rotate instantly by 90 degrees, then axis.Value will be reset to 0 because camera is now looking there.

    In worldspace binding mode, axis.Value is relative to worldspace +Z, and axis.Value will hold whatever you put there.
     
    Last edited: Dec 4, 2020
  9. mannyhams

    mannyhams

    Joined:
    Feb 6, 2015
    Posts:
    34
    Hi there, sorry to revive this thread so late but I've got a similar concern and a followup.

    I want to rotate the freelook cam 90 degrees on a button press (Q or E), smoothly.

    1) The following is what I think you were describing above and does seem to work, but I'm new to Unity/C# so does this look right?

    Code (CSharp):
    1. public class CamRotationCinemachineExtension : CinemachineExtension
    2. {
    3.  
    4.     private void Update()
    5.     {
    6.         float rotationDelta = Input.GetAxis("Rotation");
    7.         if (rotationDelta == 0f) return;
    8.  
    9.         AdjustRotation(rotationDelta);
    10.     }
    11.  
    12.     ...
    13.    
    14.     private void AdjustRotation (float delta)
    15.     {
    16.         float angle = delta > 0 ? 90f : -90f;
    17.         ((CinemachineFreeLook) VirtualCamera).m_XAxis.Value += angle;
    18.     }
    19. }
    2) This immediately changes the camera rotation, whereas I want a smoothed transition (ease in, ease out). Is there an API I can leverage so that the transition uses the `Acccel Time` and `Decel Time` values set in the Unity editor? Or is that something I should implement myself in code? I'll explore the API a little more and then go with the latter if I don't hear back.

    Thanks!
     
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    m_XAxis.Value gives you direct control over the rotation. m_XAxis.m_InputAxisValue is meant to take the user input, which then gets smoothed out using the accel/decel to generate the axis Value. However, in your case you are trying to rotate a specific amount so it will be tricky to provide just the right amount of fake user input.

    Probably the best solution is for you to drive m_XAxis.Value directly, as you are doing, but use Mathf.SmoothDampAngle to get there gradually.

    https://docs.unity3d.com/ScriptReference/Mathf.SmoothDampAngle.html
     
    mannyhams likes this.
  11. mannyhams

    mannyhams

    Joined:
    Feb 6, 2015
    Posts:
    34
    Great, thanks very much for the quick reply!
     
  12. mannyhams

    mannyhams

    Joined:
    Feb 6, 2015
    Posts:
    34
    Hm, now I'm confused by
    Mathf.SmoothDampAngle
    's behavior.

    Initially, it does move towards the target value by progressively larger steps on each invocation - that's fine and good. But the size of the steps continue to increase so that the target value is passed, rather than decreasing as the target is approached.

    Apologies for WIP code:

    Code (CSharp):
    1. using System;
    2. using Cinemachine;
    3. using UnityEngine;
    4.  
    5. public class CamRotationCinemachineExtension : CinemachineExtension
    6. {
    7.     private enum RotationDirection
    8.     {
    9.         None,
    10.         Left,
    11.         Right,
    12.     }
    13.  
    14.     private struct RotationRequest
    15.     {
    16.         public RotationDirection Direction;
    17.         public float TargetRotation;
    18.         public bool Complete;
    19.     }
    20.  
    21.     private RotationRequest _rotationRequest;
    22.     private float _rotationVelocity = 0f;
    23.     private CinemachineFreeLook _vCam;
    24.  
    25.     public float smoothTime = 0.3f;
    26.     public float maxSpeed = 10f;
    27.  
    28.     protected override void PostPipelineStageCallback(CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage,
    29.         ref CameraState state, float deltaTime)
    30.     {
    31.         _vCam = (CinemachineFreeLook) VirtualCamera;
    32.     }
    33.  
    34.     private void Update()
    35.     {
    36.         AdjustRotation(Input.GetAxisRaw("Rotation"));
    37.     }
    38.  
    39.     private void AdjustRotation(float delta)
    40.     {
    41.         RotationDirection direction = delta == 0f ? RotationDirection.None :
    42.             delta > 0f ? RotationDirection.Right : RotationDirection.Left;
    43.  
    44.         bool isRotationDone = _rotationRequest.Complete && direction == RotationDirection.None;
    45.         if (isRotationDone)
    46.         {
    47.             if (_rotationRequest.Direction == RotationDirection.None) return;
    48.  
    49.             _rotationRequest = new RotationRequest {Direction = direction, TargetRotation = 0f, Complete = true};
    50.             return;
    51.         }
    52.  
    53.         bool isNewRotationRequest =
    54.             direction != _rotationRequest.Direction && direction != RotationDirection.None;
    55.         if (isNewRotationRequest)
    56.         {
    57.             float rotation = direction == RotationDirection.Right ? -90f : 90f;
    58.             float targetRotation = _vCam.m_XAxis.Value + rotation;
    59.             _rotationRequest = new RotationRequest
    60.                 {Direction = direction, TargetRotation = targetRotation, Complete = false};
    61.         }
    62.  
    63.         AdjustRotation();
    64.     }
    65.  
    66.     private void AdjustRotation()
    67.     {
    68.         float dampenedRotation =
    69.             Mathf.SmoothDampAngle(_vCam.m_XAxis.Value, _rotationRequest.TargetRotation, ref _rotationVelocity,
    70.                 smoothTime, maxSpeed);
    71.         _vCam.m_XAxis.Value += dampenedRotation;
    72.         _rotationRequest.Complete = Math.Abs(_vCam.m_XAxis.Value - _rotationRequest.TargetRotation) < 1f;
    73.     }
    74. }
    Probably I'm making some rookie mistake, but I can't see it in the docs/code yet. I've tried playing with
    smoothTime
    and
    maxSpeed
    with no success. Any ideas?

    EDIT: wordsmithing
     
    Last edited: Dec 5, 2020
  13. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Sorry for not replying sooner, this thread dropped off my radar.
    Could the problem be that this line
    Code (CSharp):
    1. _vCam.m_XAxis.Value += dampenedRotation;
    should be this?
    Code (CSharp):
    1. _vCam.m_XAxis.Value = dampenedRotation;
     
    twitchfactor likes this.