Search Unity

Question How do you slot in a modifier to smooth out motion?

Discussion in 'Cinemachine' started by laurentlavigne, Jun 2, 2023.

  1. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,334
    I have a camera rig that snaps between 6 cameras, some fly, others orbit and some handle 3rd and 1st person.
    The cameras are tunes to give the player very tight control so if I record this it looks as jittery as a competitive FPS -- very jarring.
    To make the cinematic presentation I'd like to smooth that up but would rather not destroy the tuning I did.
    Also for the final game there would be value in having a cinematic camera mode for twitch.
    Like in 3dsmax geometry modifier, ideally you'd be able to slot in a motion modifier at the root CinemachineBrain but there is no such thing. Something like a dampened rubberband constraint.
    So what's the CM way of doing this? v 2.8.9
     
    Last edited: Jun 2, 2023
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    I'm having trouble understanding your question.

    What is the source of the jitter? Is it only when recording? Is it in each camera? Does it have to do with blending? What does the jitter look like?

    Are you wanting to do some kind of global damping to smooth out the jitter? This is possible, but IMO it's not a great idea because it will affect the tuning of the cameras indiscriminately. Much better would be to isolate to root cause of the jitter and fix that. If the cameras are jittering, then something is wrong. Don't just patch it by blurring everything.

    That said, if you really insist on post-processing the camera positioning, you can do it with a custom behaviour that listens to CinemahineCore.CameraUpdatedEvent. This is fired whenever CMBrain positions the camera. You can post-process the camera's transform at that point.
     
  3. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,334
    Ok I'll explain more:

    Gameplay camera is always designed to respond to user input with no lag, as a result it feels right but is ultra jerky vomit inducing if you're an onlooker. Look up doom3 or quake competitive on youtube and you'll see what I mean.

    You can see that this is unusable in a trailer so a thing we do traditionally is smooth the camera at the root.

    Syntax in CM being what it is, what's the script for that?
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Thanks for the explanation, it's helpful.
    As I mentioned, you can post-process the camera transform after CM is done with it. No fancy syntax required. Just do whatever you would have done if CM were not present.
     
  5. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,334
    Please provide a script example.
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    So do that. It's not up to me to write your code. If you put that code in the LateUpdate of a behaviour whose script update order is greater than CMBrain, then it will execute every frame after CM is done modifying the main camera's transform, and you can use that opportunity to apply your custom special smoothing to it.

    Or are you asking for an example of how to hook into CinemachineCore.CameraUpdatedEvent?
     
  7. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,334
    Yes. Because this doesn't have any effect even though the code is stepping after F1 is pressed.
    Code (CSharp):
    1.     void OnEnable()
    2.     {
    3.         CinemachineCore.CameraUpdatedEvent.AddListener(CMSmoother);
    4.     }
    5.  
    6.     void OnDisable()
    7.     {
    8.         CinemachineCore.CameraUpdatedEvent.RemoveListener(CMSmoother);
    9.     }
    10.  
    11.     bool       _cinematicSmoothToggle;
    12.     Vector3    _velocityPos = Vector3.zero;
    13.     public float maxDegreesDelta = 0.1f,
    14.         smoothTime                = 0.01f;
    15.  
    16.     void CMSmoother(CinemachineBrain brain)
    17.     {
    18.         if (Input.GetKeyDown(KeyCode.F1)) _cinematicSmoothToggle = !_cinematicSmoothToggle;
    19.         if (_cinematicSmoothToggle)
    20.         {
    21.             transform.position = Vector3.SmoothDamp(transform.position, brain.CurrentCameraState.RawPosition, ref _velocityPos, smoothTime);
    22.             transform.rotation = Quaternion.RotateTowards(transform.rotation, brain.CurrentCameraState.RawOrientation, maxDegreesDelta * Time.deltaTime);
    23.         }
    24.     }
     
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Am I correct to presume that the behaviour is added to the main camera? And that camera has the CM Brain on it?
    If so, then you are hooking into the event correctly.

    The problem here is that the transfom already has the values from brain's camera state, so lerping between them will have no effect. I think a better approach would be to store the position from the previous frame (or a travelling window of frames) and lerp from there towards the current transform position. You don't need to look at the brain since all values have already been pushed to the camera.
     
  9. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,334
    Got it, that makes sense. It works, thanks.

    How do you smooth aim, Slerp?
     
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Yes, slerp will generally work. You can do something very naive, like slerp half way every frame. That will make a decent smooth.