Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

How to avoid the offset between two freelook virtual cameras in a tps camera system?

Discussion in 'Cinemachine' started by vamky, Nov 12, 2018.

  1. vamky

    vamky

    Joined:
    Aug 9, 2014
    Posts:
    70
    HI:

    So I am trying to get a TPS prototype working, and my goal with the camera system is to recreate the experience you will have in any popular third person shooter. I have successfully hooked up two freelook camera with identical rig setting and screen x offset with a state driven camera. (The only difference they have is field of view.) Everything from movement and rotation is working nicely except this one problem I have:

    When aiming, the aim state freelook camera has a clear offset from the not aim state camera, even if they have the same follow and look at target and input.

    I looked at Warframe and found they solved this problem, their normal camera and aim camera has almost no offset except the FOV difference. As you can see in my attachment.
    WF_Camera_Normal.png WF_Camera_Aiming.png

    So, how should I avoid the offset in this scenario?
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,745
    What do you mean when you say "screen x offset with a state driven camera"?
    How do you implement the screen X offset?

    The only way to get what you're looking for is to ensure that when you switch between Aim and Normal, the vcam does not rotate at all, and does not move except along its Z axis. This can be done with CM, but you have to take considerable care with the Aim settings and the orbits.
     
  3. vamky

    vamky

    Joined:
    Aug 9, 2014
    Posts:
    70
    Hi Gregorl

    The (screen X) thing is the screen x variable on each rig of the freelook vcam. Which I set to 0.35 on all rigs so the character is shifted to the left side of the screen to get that TPS over shoulder feel.

    I have put up an example project to help to illustrate my point.
    In the asset folder, there are two scenes. In the CinemachineOverShoulder scene you can press space bar to shift between normal and aim camera. In the HackOverShoulder scene, you will find my little hack warframe camera, and as you can see when you adjust the fov value, the center of the screen does not get offset to another position.

    I think my hack camera works because:
    1. the camera simply looks ahead and follow the rotation of the mount. (In cinemachine you can set vcam to follow a target's transform but not rotation)
    2. the horizontal rotation circle around the character, but vertical rotation circle around the mount.

    thanks for replying!

    PS: After playing around a little more with the state driven 2 freelook cameras setup, I found another problem, that is when one of the freelook cameras is live, the other one stuck in the state when it went standby, and will cause a very big offset when two cameras are actually facing two directions. Is there a way to solve this?
     

    Attached Files:

    Last edited: Nov 16, 2018
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,745
    You need to be careful with your settings.
    First, and most importantly, make sure that both FreeLooks have InheritPosition checked:

    upload_2018-11-16_10-22-21.png

    This forces the incoming FreeLook to be warped to the correct place on the orbit to match the outgoing.

    Next, you have to tune the screen position. Because you're changing the focal length and because the target is off-center, if you want the center of the screen to remain fixed you can't have the target at a constant screen point across different FOVs - it's physically impossible unless the FOV remains fixed. Cinemachine puts the LookAt target at the point you specify. It doesn't care about screen center.

    In your example, I tried setting the screen X to 0.35 for the normal cam, and 0.25 for the Aim cam. That came pretty close. You'll have to do similar tuning for the Y position.

    A better and less finicky approach to solving this problem is to put all targets at screen center, then add a CM extension to shift the whole camera at the end of the CM pipeline, after all the calculations have been done.

    Here is an extension that does that. You can add it to the SDC, and it will affect all the child FreeLooks.
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. /// <summary>
    5. /// An add-on module for Cinemachine Virtual Camera that adds a final offset to the camera
    6. /// </summary>
    7. [AddComponentMenu("")] // Hide in menu
    8. public class CinemachineCameraOffset : CinemachineExtension
    9. {
    10.     [Tooltip("Offset the camera's position by this much (camera space)")]
    11.     public Vector3 m_Offset = Vector3.zero;
    12.  
    13.     protected override void PostPipelineStageCallback(
    14.         CinemachineVirtualCameraBase vcam,
    15.         CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    16.     {
    17.         // Apply after the camera has been aimed.
    18.         // To apply offset before the camera aims, change this to Body
    19.         if (stage == CinemachineCore.Stage.Aim)
    20.         {
    21.             Vector3 offset = state.FinalOrientation * m_Offset;
    22.             state.ReferenceLookAt += offset;
    23.             state.PositionCorrection += offset;
    24.         }
    25.     }
    26. }
    Finally, you'll get best results if you add an empty game object inside your character, to serve as a LookAt and Follow target. Place it in the center of the head, and set all the LookAt offsets in the vcam to 0. Adjust your orbits to accommodate the new target pos. Having the target be actually at the center of the orbits (instead of using orbits that are offset vertically as you have) will maximize CM's ability to blend seamlessly between FreeLook targeting that character.
     
    vamky likes this.
  5. vamky

    vamky

    Joined:
    Aug 9, 2014
    Posts:
    70
    Thanks! That's very helpful!
     
  6. vamky

    vamky

    Joined:
    Aug 9, 2014
    Posts:
    70
    Hi Gregorl:

    Just a follow up after my further experiments after the weekend. Here are my results:

    following your advice, I can achieve zero offsets between 2 cameras when their aims are all in the center of the screen. However, the script you provided does not work as intended as it will add offset everytime the live vcam is changed (change between state.body and state.aim produce slight different results). Also in a third person overshoulder environment, it should not be the aim that shift position to the offset but the player's position on the camera, otherwise you will not able to do quick and precise shooting.

    I also updated my hack camera with a set of state-driven vcams to work with my custom rig, please check it out.
     

    Attached Files:

  7. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,745
    In your project, you did 2 things to make the Offset script not work properly:
    1. You changed the CameraOffset script to apply the offset after the Body stage. To get the correct behaviour, you have to leave it the way it was (i.e. apply the offset after the Aim stage)
    2. You changed the FreeLooks to SimpleFollow binding mode. An X offset won't work in SimpleFollow. You have to leave the binding mode on WorldSpace.
     
  8. vamky

    vamky

    Joined:
    Aug 9, 2014
    Posts:
    70
    Yes those setting solved most of the problems I have, only 1 left:
    When 1 freelook vcam moves to its lower rig, then the other one goes live and move to its own higher rig, if you switch the live camera again, there will still be an offset.

    Thanks again!