Search Unity

Proper way to 'reset' follow camera?

Discussion in 'Cinemachine' started by AustinDrozin, Sep 18, 2019.

  1. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    Right now I have a camera that follows and aims at a 3rd person character controller. I have a function where the player can teleport back to a place they saved instantaneously. The problem is the camera kind of freaks out. It seems to be an issue with the Aim portion.

    I took out the art assets and character. Every time the camera rotates like mad is when I am pressing the teleport/return button. It just sends the sphere back to the starting position. I'd like the camera to reset back to a similar location as the start of the gif.



    How do I get this to just reset like normal similar to right at the beginning of the scene start?
     
  2. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
  3. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    It looks to me as though you're just warping the character to the start position. The camera is trying to follow, and because of the damping it takes time. You need to tell the camera to cancel the damping because this is a warp, and not just a fast movement that it has to follow.
    When you warp the player position, add this call: vcam.OnTargetObjectWarped(), to inform the vcam of the situation.
     
  4. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    oh so that function will turn off damping?
     
  5. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    For that frame, yes. It will preserve the target-to-vcam spatial relationship by applying to the vcam the same position delta as the target, bypassing all damping for that frame.

    Normally that call is used when you want a continuous-looking follow to happen across a warp of the target. A common use-case is infinite worlds when you wrap around.

    If you're trying to just start over, it might be easiest to disable the vcam re-enable it. That will cancel all previous state and make the vcam start over. While it's disabled, you can also reposition the vcam if you want to give it an initial starting point.
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Correction: Disabling/re-enabling the vcam won't work because the vcam's OnEnable() method won't get called until the next frame. Try instead to reset the vcam by setting vcam.PreviousStateIsValid = false. That should make the vcam snap to the new spot.
     
  7. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    Hm I tried both ways, but nothing seems to be happening. Still does the same thing.

    Code (CSharp):
    1. vCam.OnTargetObjectWarped(t, posDelta);
    Code (CSharp):
    1. vCam.PreviousStateIsValid = false;
    podDelta is just subtracting the old position from the new position right?
     
    Last edited: Sep 29, 2019
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Yes.

    Can you show me the entire code that handles the reset? vCam.PreviousStateIsValid = false should do the job.
     
  9. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    I commented out a function on the last line that called 'vCam.PreviousStateIsValid = false' in another class. That's all it does though.

    Code (CSharp):
    1. public void Respawn(Vector3 p, Quaternion r)
    2. {
    3.         Vector3 posDelta = p - transform.localPosition;
    4.  
    5.         transform.localPosition = p;
    6.         transform.rotation = r;
    7.         rb.velocity = new Vector3(0, 0, 0);
    8.  
    9.         vCam.PreviousStateIsValid = false;
    10.  
    11.         //camMovement.ResetCamera(transform, posDelta);
    12. }
     
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Can you prove that vCam is actually the current active vcam? Also can you show me the inspector for the vCam, and for the CM Brain?
     
  11. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    Yes it is the only vCam in the scene.

    upload_2019-9-30_22-40-34.png
    upload_2019-9-30_22-40-57.png
     
  12. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    Need to see anything else?
     
  13. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    It all looks good to me. I don't see off the top of my head why vcam.PreviousStateIsValid = false wouldn't work, if you're calling Respawn(). Can you see in the scene view that the player pops back to the origin but the vcam travels gradually? Does the effect disappear if you set the vcam's damping (all of it) to 0?
     
  14. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    So I set all the damping and look ahead to 0, but it doesn't go away completely. The rotation is still wonky, but only a tad. It doesn't reset completely and it still lerps over to the spawn point(not a warp).
     
  15. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    So you're saying that with no lookahead and no damping (aim or body) you're not getting a hard follow? That's impossible. Turn off the noise too. If at that point the vcam isn't attached as though with a hard rod to your player, then there is something else interfering.
     
  16. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    upload_2019-10-3_9-5-20.png

    https://thumbs.gfycat.com/TheseAdorableBaiji-mobile.mp4


    Seems like the position damping makes the position a little better. Not perfect.

    The rotate is still pointing to the direction it was before the warp though. Would the only solution be to turn off all damping for one frame then reset the position of the vcam manually?
     
  17. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    With those vcam settings, the camera should be 100% locked to the target - there should be no frame that doesn't have the target firmly positioned in the center of the game view.

    Yet, in your clip, there is this frame:

    upload_2019-10-3_9-19-43.png

    Conclusion: the camera target and the player are not the same game object. Camera target and player are not in the same position. Is that the case?
     
    zeropointblack likes this.
  18. AustinDrozin

    AustinDrozin

    Joined:
    Jun 8, 2016
    Posts:
    43
    Wow ok make me look dumb... lol. im ashamed

    I was totally overlooking the fact I changed the target to be a separate transform... That other cameraTarget is being lerped towards the player position.

    Thank you! It all works properly now.
     
    Gregoryl likes this.
  19. ABerlemont

    ABerlemont

    Joined:
    Sep 27, 2012
    Posts:
    67
    My use case : I teleport the player on a "room change" and I wanted the camera to seemlessly follow the player (and NOT lerp to the new position).

    This answer was the way to go for me.
    Thanks !
     
    Gregoryl likes this.
  20. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    392
    The PreviousStateIsValid tricks doesn't seem to work every time when you're using a TargetGroup.
    Most likely because it also lags behind the actual transform it's following or something

    I fixed it like this.
    I changed the vcam smoothing to 0 so we get instant follow for a small duration.

    Code (CSharp):
    1.  
    2. //When warping the player over long distances, the camera lerps the entire distance till the player
    3. //We want instant teleport of the camera over a long distance
    4. public IEnumerator WarpCamera() {
    5.             //This trick works if you're following the transform directly but with a target group it doesnt seem to work
    6.             //CameraManager.singleton.vCam.PreviousStateIsValid = false;
    7.  
    8.             ChangeCameraDamping(0);
    9.  
    10.             //yield return null;
    11.             yield return new WaitForSeconds(1);
    12.  
    13.             ChangeCameraDamping(1);
    14. }
    15.  
    16. //get correct transposer depending on your cam settings
    17. public void ChangeCameraDamping(float amount) {
    18.             vCam.GetCinemachineComponent<CinemachineFramingTransposer>().m_XDamping = amount;
    19.             vCam.GetCinemachineComponent<CinemachineFramingTransposer>().m_YDamping = amount;
    20.             vCam.GetCinemachineComponent<CinemachineFramingTransposer>().m_ZDamping = amount;
    21. }
    22.  
     
    Last edited: Dec 30, 2020
    Lorrak and Curipoc like this.
  21. Curipoc

    Curipoc

    Joined:
    Jan 5, 2021
    Posts:
    1
    Worked great, thank you.
     
  22. mntngoatgames

    mntngoatgames

    Joined:
    Aug 25, 2020
    Posts:
    4
    So, this is the closest I've been able to get to having a seamless warp so far, but it still isn't quite right. The camera moves to the right spot, but the whole screen blinks (I'm guessing that it moves to the wrong spot and then with 0 smoothing moves again to the lookahead distance).

    Code (CSharp):
    1. private void LateUpdate()
    2.     {
    3.         Vector3 playerPos = player.transform.position;
    4.         playerPos.z = 0f;
    5.         playerPos.y = 0f;
    6.         playerPos = playerPos * -1;
    7.  
    8.  
    9.         if (playerPos.magnitude > threshold && player.MovementState.CurrentState == CharacterStates.MovementStates.Running)
    10.         {
    11.  
    12.             foreach (GameObject g in SceneManager.GetActiveScene().GetRootGameObjects())
    13.             {
    14.                 g.transform.position += playerPos;
    15.             }
    16.  
    17.             StartCoroutine(WarpCamera());
    18.             int numVcams = CinemachineCore.Instance.VirtualCameraCount;
    19.             vCam.OnTargetObjectWarped(transform, playerPos);
    20.             //vCam.PreviousStateIsValid = false;
    21.             camRig.transform.position -= playerPos;
    22.             confiner.transform.position -= playerPos;
    23.  
    24.         }
    25.  
    26.     }
    27.  
    28.     public IEnumerator WarpCamera()
    29.     {
    30.         ChangeCameraDamping(0);
    31.         ChangeCameraSmoothing(0);
    32.  
    33.         yield return new WaitForSeconds(1);
    34.  
    35.         ChangeCameraDamping(1);
    36.         ChangeCameraSmoothing(15);
    37.     }
    38.  
    39.     public void ChangeCameraDamping(float amount)
    40.     {
    41.         transposer.m_XDamping = amount;
    42.         transposer.m_YDamping = amount;
    43.         transposer.m_ZDamping = amount;
    44.     }
    45.     public void ChangeCameraSmoothing(float amount)
    46.     {
    47.         transposer.m_LookaheadSmoothing = amount;
    48.     }
    49.  
    I only have the one vCam in the scene. I know that the vCam and Transposer references are correct.

    Any ideas why this might not be working with the OnTargetObjectWarped method as intended?
     
  23. mntngoatgames

    mntngoatgames

    Joined:
    Aug 25, 2020
    Posts:
    4
    Ok, so I figured it out. Another one of my scripts was making it so that the vCams follow target wasn't actually the object I thought it was. I updated the script to make the OnTargetObjectWarped function use the right target and it worked.

    Now I just need to figure out how to keep my parralax layers from getting all screwed up when the camera moves back. They're being moved the same amount as everything else so I'm not sure why it's glitching.
     
  24. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,332
    @Gregoryl, is this something that's becoming easier in CM3?

    Every single project I work with Cinemachine on has the same problem - there's no simple, surefire way to just say "move the vcam to it's current target position/rotation instantly". And every game needs that, without fail. From the smallest game jam to the largest production, it's always required, and always an annoyance.

    The PreviousStateIsValid = false trick is bad since it's not instantaneous. It's also incredibly hard to discover, so even if it it's enough for my game, I have to google to figure out what to do every single time.
     
  25. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    PreviousStateIsValid = false is the way to do it. I don't know what you mean by "instantaneously". Setting that will position the camera at the end of the current frame, when the cameras are positioned. If you need to do some processing that requires knowledge of the camera's position, you must do that at the end of the frame, after the cameras are positioned, which is how you would have to do it during normal game frames.

    For discoverability: what do you suggest?
     
  26. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,332
    Something better than
    PreviousStateIsValid = false;
    ! There's nothing at all intuitive about "if the state is invalid, then we jump to the end".

    The intent of the user is to skip all interpolation and teleport the camera to the position/rotation it's moving towards, so TeleportToTargetPosition() or SnapToEnd() or anything that matches what the user's trying to do would be a lot better.
     
  27. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    I dunno. Jump to the end of what? When damping is enabled, the camera moves gradually from its current position to the target one. If the camera forgets where it is (i.e. forgets its current state) then it has no choice but to go directly to the target position, since there is nowhere to lerp from.

    I suppose we can add some sort of function call that invalidates the state, but so far I'm not sold on the name. What do you think about CancelDamping()?

    And what about it being not instantaneous? Can you elaborate a little on why that's a problem for you?
     
    Last edited: Nov 1, 2023
  28. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,332
    CancelDamping could work. I think the important thing is to ask "what's the user going to look for?". What you said when you were describing the feature is:
    , so maybe that's the correct name?
    GoDirectlyToTargetPosition()
    is pretty intuitive.


    Code that's synchronous is a lot easier to reason about than asynchronous code! The whole "wait until LateUpdate so we're sure that we move after the target" thing can add a bunch of complication, and since we're generally calling this code right after having teleported the target, it's not necessary.

    If it's a problem that the object I'm following/looking at is a frame out of date, then that's a problem I've created by calling the method without thinking about that problem. That's on me.