Search Unity

Adding an offset to camera final position

Discussion in 'Cinemachine' started by xDavidLeon, Aug 2, 2017.

  1. xDavidLeon

    xDavidLeon

    Joined:
    Jun 9, 2014
    Posts:
    123
    Hi there,

    Working on a 3rd person camera, I'd like the camera to follow and aim at the player, but move it 0.5 units to the (final) camera transform.right vector in order to have the player slightly to the left.

    Example:

    Changing the camera Aim -> Tracked Object Offset or Aim -> Screen X, just rotates the camera but doesn't translate it.

    I can also change the Follow Target so that it follows an empty GameObject that always stays 0.5f to the right of the player, but that would make the camera pivot around that offset instead of the player.

    I can make the camera Follow an empty GameObject with this script attached to obtain the desired result:

    Code (CSharp):
    1. public class FollowTargetWithCameraOffset : MonoBehaviour
    2.     {
    3.         public Transform target;
    4.         public Vector3 offset = new Vector3(0f, 0.0f, 0f);
    5.         public Vector3 cameraOffset = new Vector3(0f, 0.0f, 0f);
    6.  
    7.         private Camera cam;
    8.         private Vector3 position;
    9.  
    10.         private void FixedUpdate()
    11.         {
    12.             if (target == null) return;
    13.  
    14.             if (cam == null) cam = Camera.main;
    15.             position = target.position + offset;
    16.  
    17.             if ( cam != null ) position += cam.transform.right * cameraOffset.x;
    18.  
    19.             transform.position = position;
    20.             transform.forward = target.forward;
    21.         }
    22.     }
    With that solution, I'm getting the camera Right vector so that the target always stays to the right of the character, but as it depends on the Camera.transform.right, and the Cinemachine camera is chasing after this same object, it creates jerkiness as one depends of the other. Changing the Script Execution Order doesn't seem to fix this issue.

    So the final questions is: Is there any way to add a World Offset to the final position of a Cinemachine Free Look camera?
     

    Attached Files:

    sd1515 likes this.
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,712
    Try this:
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. /// <summary>
    5. /// An add-on module for Cinemachine Virtual Camera which post-processes
    6. /// the final position of the virtual camera.
    7. /// </summary>
    8. [ExecuteInEditMode]
    9. [SaveDuringPlay]
    10. public class CameraOffsetter : MonoBehaviour
    11. {
    12.     [Tooltip("How much to offset the camera, in camera-local coords")]
    13.     public Vector3 m_Offset = Vector3.zero;
    14.  
    15.     private void Start()
    16.     {
    17.         OnEnable();
    18.     }
    19.  
    20.     private void OnEnable()
    21.     {
    22.         VirtualCamera = GetComponent<CinemachineVirtualCameraBase>();
    23.         if (VirtualCamera == null)
    24.         {
    25.             Debug.LogError("CameraOffsetter requires a Cinemachine Virtual Camera component");
    26.             enabled = false;
    27.         }
    28.         else
    29.         {
    30.             VirtualCamera.AddPostPipelineStageHook(PostPipelineStageCallback);
    31.             enabled = true;
    32.         }
    33.     }
    34.  
    35.     private void OnDestroy()
    36.     {
    37.         if (VirtualCamera != null)
    38.             VirtualCamera.RemovePostPipelineStageHook(PostPipelineStageCallback);
    39.     }
    40.  
    41.     public CinemachineVirtualCameraBase VirtualCamera { get; private set; }
    42.  
    43.     private void PostPipelineStageCallback(
    44.         CinemachineVirtualCameraBase vcam,
    45.         CinemachineCore.Stage stage, ref CameraState state, CameraState previousState, float deltaTime)
    46.     {
    47.         if (enabled)
    48.         {
    49.             if (stage == CinemachineCore.Stage.Aim)
    50.             {
    51.                 state.PositionCorrection += state.RawOrientation * m_Offset;
    52.             }
    53.         }
    54.     }
    55. }
    56.  
    Add it to your vcam.
     
    OscarLeif likes this.
  3. xDavidLeon

    xDavidLeon

    Joined:
    Jun 9, 2014
    Posts:
    123
    Awesome, will try tomorrow morning.

    Is this code part of the the next Cinemachine release?
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,712
    no, I just cooked it up for you
     
  5. xDavidLeon

    xDavidLeon

    Joined:
    Jun 9, 2014
    Posts:
    123
    Looks like it works perfectly, thank you!

    In any case, I can't think of a single game rig that *doesn't* use camera offset options, so please think about adding public Vector3 offset or something like that to the base Free Look camera :)

    Thank you!
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,712
    @xDavidLeon Thinking about it more, maybe the solution I gave you was overkill. Would you not get exactly the same result by setting the Composer Screen X (in the 3 rigs) to put the character a little to the left on the screen?

    [Edit} You would also have to set the FreeLook Heading Bias to compensate for this, so that the character forward will match the camera forward.

    Like this:
     

    Attached Files:

    Last edited: Aug 3, 2017
  7. xDavidLeon

    xDavidLeon

    Joined:
    Jun 9, 2014
    Posts:
    123
    That's also a way to do it, although from a UX point of view, is way easier to just put the desired offset instead of playing around with angles :p
     
  8. Radiago

    Radiago

    Joined:
    Jan 7, 2014
    Posts:
    18
    Just wanted to pipe in here in support of this solution instead of the composer/bias one. In my game I dynamically move the look at point in front of the character a little bit based on their speed so that when they're turning, especially to the left (which is the side of the screen they are on) they shift on screen to show more of what's ahead of them. This code allows me not to have to re-do the math of the bias in that case, which is really nice. Thanks for writing this snippet, it's very useful!
     
  9. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,712
    Please note that the above snippet needs to be adapted in order to work with the new CM 2.1 (RC available here: https://forum.unity.com/threads/cm-v2-1-release-candidate.497202/), because the API has changed.

    I would strongly recommend upgrading, not least because the FreeLook is significantly improved. See the long list of features.

    To make it extra easy for you, here is the new CameraOffsetter behaviour, modified to work with CM 2.1. Notice how much smaller it is :cool:

    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3. /// <summary>
    4. /// An add-on module for Cinemachine Virtual Camera which post-processes
    5. /// the final position of the virtual camera.
    6. /// </summary>
    7. [ExecuteInEditMode]
    8. [SaveDuringPlay]
    9. public class CameraOffsetter : CinemachineExtension
    10. {
    11.     [Tooltip("How much to offset the camera, in camera-local coords")]
    12.     public Vector3 m_Offset = Vector3.zero;
    13.     protected override void PostPipelineStageCallback(
    14.         CinemachineVirtualCameraBase vcam,
    15.         CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    16.     {
    17.         if (enabled && stage == CinemachineCore.Stage.Aim)
    18.             state.PositionCorrection += state.RawOrientation * m_Offset;
    19.     }
    20. }
     
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,712
    @Radiago In CM 2.1, the composer has a "lookahead time" setting, which does pretty much what you describe, out of the box. Give it a spin and let me know if it's helpful.
     
  11. FuraBolos

    FuraBolos

    Joined:
    Jan 19, 2018
    Posts:
    16
  12. jorg3n3gr3iros

    jorg3n3gr3iros

    Joined:
    Aug 19, 2016
    Posts:
    7

    Hi!
    This code work so fine. But, if I use the Cinemachine Collider with this, does not work perfectly because the Cinemachine Collider ignores the offset.
    Do u have a solution for this problem?
     
  13. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,712