Search Unity

[SOLVED] How to make a 1:1 migration from a custom script follow camera to a Cinemachine vcam

Discussion in 'Cinemachine' started by NeatWolf, May 21, 2019.

  1. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    Hi,

    I'm in the process of adapting some code/systems I didn't wrote to Cinemachine.
    I have a very basic interpolating script which is *perfect* to me to handle a simple 3rd person driving game with an arcade feel.

    And, I need to port it as is to Cinemachine.
    Yet, I really can't find how to replicate it perfectly. I'm tempted to just use it as it is, but it's now getting a matter of principle :p
    Could you please help me?

    Setup:
    a CameraRig gameobject mounted(child) on the Target, with this local transforms:


    And a VehicleCamera with this transform. VehicleCamera is child of CameraRig


    Basically, the camera is looking at 1 unit above the Target, leaning down 20 degrees, 4 units backwards with that angle.

    The camera script is easy (stripping some code):

    void Awake(){
    cameraPositionOffset = rig.localPosition;
    cameraRotationOffset = rig.localEulerAngles;
    }

    void FixedUpdate() {
    rig.position = Vector3.Lerp(rig.position, transform.position + cameraPositionOffset, Time.deltaTime * followSpeed);
    rig.rotation = Quaternion.Lerp(rig.rotation, Quaternion.Euler(transform.eulerAngles + cameraRotationOffset), Time.deltaTime * rotationSpeed);
    }


    followSpeed is 16 and rotationSpeed is 4

    I set up a simple vcam like this, result of some guesswork to compensate for the different interpolation:

    But the feel is completely different. In editor the camera coords are almost similar. Also, the camera seems to be a bit stuttering if I put all the dampings to zero.
    I basically killed the Soft and Dead Zone by zeroing them.

    And, that's all.

    Probably it's just better to write two simple, custom aim/move modules?

    The project is quite big, but I can try to shrink it a lot as a package if it may help. It's basically the 2 objects nested as above and a single script on the Target, ruling the camera.

    Since I have multiple vehicles, I'm also basically decoupling the camera from the vehicle hierarchy, and allowing me to blend in/out from the track flyby and the adversaries, so Cinemachine seems like the right direction to take.
     
    Last edited: May 21, 2019
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    It's very easy to convert a custom camera script to Cinemachine. Keep the custom script, just delete (or disable) the Camera component, and replace it with a CinemachineVirtualCamera with DoNothing in Aim and Body. That will turn off the procedural code and allow the vcam's position and aim to be 100% controlled by your script.

    Then, create a top-level Camera with a CinemachineBrain, and when your vcam is active that Camera will track it perfectly, and it will be able to blend with other vcams, and have all the good stuff that Cinemachine brings.
     
    Zyrathius and NeatWolf like this.
  3. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    Thanks Gregory!
    It completely fled over my mind I could just disable the camera logic and do everything from the script (attached on each vehicle)

    I really didn't like that script tho, since I also wanted to use features like Cinemachine Collider, and decouple the vehicle prefab from the camera logic (even if, for very different vehicles I guess I will have to create some ScriptableObject config files to handle minor adjustments, or create prefab variants)

    In the meantime I did my best to replicate the same stiff yet ultimately smooth feel of the original code by using components way more complex than those 2 lines :p

    All it took was to get the actual original composite offset from the target to the camera (and put it in the body offset), and push the ScreenY down (doing some typical binary search attempts) until it was exactly 20 degrees, zeroing most of the values but the Yaw damping and here's the result:


    It's not a 1:1 replica, also because I peeked into the code of the Transposer/Composer and the damping gets done differently, also using Slerp as opposed as the Lerp of the original script, but It's really close to the original.

    I wish I could somehow preserve the relative Pitch of the camera relative to the target, since if I increase any damping too much the camera gets dragged to the ground when at full speed, and almost above when the car is still.
    The above setup prevents that, but adding some extra vertical damping would allow the camera to ignore most of the jumps the car can do.
    Currently the camera is almost locked to the targets' Y position, so pressing the jump button makes the camera jump with the same intensity, somehow detracting from the general feel of the action.

    Sure, increasing the Soft Zone Height would allow for some extra margin, but it could also mean that the camera could just sit down in place and get dragged only when the car gets way too distant.

    Is there a way to lock the camera relative angle to the target and its distance from it, even temporarily (since I may need to shorten it when moving inside tunnels)? Should I use a camera state for that?
     
    Last edited: May 21, 2019
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    With the DoNothing vcam controlled by your custom script, you can still add CM stuff like collider and noise. They will work together.

    For the replication: yes the damping is different, it will take some effort to replicate. Have you tried using the Framing Transposer in Body, and DoNothing in Aim? That will preserve the camera angle. However, that will be world-space. You'll have to add a custom script to set the vcam's Y rotation to match the target's.
     
    NeatWolf likes this.
  5. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    Thanks again Gregoryl!

    I think I got some satisfying results even forgetting about the original script.
    I peeked into the code of the Transposer and Composer, and I believe that if my OCD/matter of principle eventually kicks in, if the Body/Aim dropdown menus autopopulate by themselves if they find custom classes, I may eventually just write some classes for basic camera position/rotation lerping "just like the old days" :D , I believe it could be a little nice exercise, I'm going to share them if I do :)

    I still feel there's some subtle stuttering, almost unnoticeable due to the high frame rate, but both camera logic and vehicle logic get done in the FixedUpdate stage. I'm wondering if I should change the scripting execution order to execute the vehicle logic before cinemachine.
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    CM scripting order is default + 100, so your scripts are likely already executing before CM.
    Does the stuttering go away when damping is zero?

    And yes, you should be able to implement your own aim/follow components that use lerp.
     
    NeatWolf likes this.
  7. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    Nice! :)

    And yes, the stuttering only happened with damping >0, but there were no issues with dampening set to 0.

    Yes, everything seems to be fine there, except a postprocess plugin (Aura2) which gets executed before cinemachine. I'm unsure if the developer of Aura2 intended to execute the code relative to volumetrics/cameras before or after cinemachine. I'm going to ask just in case. I didn't expect Aura2 to be in the script execution order at all, so there must surely be a reason for that.


    Thanks for your valuable help and time @Gregoryl ! :)
     
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    If the stuttering is happening with damping, that's a sign of a problem with the animation.
    Do you want to solve that, or are you happy just setting the damping to 0?

    I'm guessing that a post-processing script wants to happen after CM has positioned the camera
     
    NeatWolf likes this.
  9. Zyrathius

    Zyrathius

    Joined:
    Dec 18, 2012
    Posts:
    20
    @Gregoryl Wow, with that simple post and a small amount of backtracking on my part, you fixed almost every issue I had been having trying to integrate Cinemachine with some camera code I had already working.

    I'm not sure why I kept missing the boat on converting a custom camera script to Cinemachine but after following your instructions above, everything is working like never before. I had been pulling my hair out almost trying to setup Cinemachine rigs to emulate what already worked, but did not even have to do all that. THANK YOU!
     
    _eternal, Gregoryl and NeatWolf like this.