Announcing Cinemachine 3.0

TLDR: Cinemachine 3.0 – a major version change – will be in pre-release for 2023.1 and full release for 2023.2.

Since Unity acquired Cinemachine back in 2016, we’ve steadily added to and improved the feature set. Cinemachine now ranks as one of Unity’s most-installed packages. So doing a full version bump is kind of a big deal and we want to make sure everyone is aware well in advance.

Cinemachine 3.0 will be in pre-release for Unity 2023.1
The upgrade will involve significant UX and API changes.

[EDIT Dec 13] Here’s a video explaining all the significant changes. [/EDIT]

What problem does Cinemachine 3 address? In a word: consistency
Cinemachine has always been a bit idiosyncratic in its implementation. The vast majority of the work in Cinemachine 3 removes these idiosyncrasies. We’ve rationalized names, removed under-the-table workarounds, simplified the UX, and generally made the entire tool “play nice” with Unity. The result is better support for features like presets and prefabs, an easier user onboarding process, less confusion for those programming against the Cinemachine API, and a clear path to grow the tool with a lot less technical debt.

Should everyone adopt Cinemachine 3?
Not necessarily. We’ve designed this as a “featureless” upgrade, meaning that we’re not trying to tempt those of you in active development to throw out your work in favor of the new tool. Rather, we recommend Cinemachine 3 for new projects, starting in 2023.2. Others should stay with 2.x, safe in the knowledge that we’ll keep providing bug fixes and support for at least the next two years.

While we will provide an updater to help upgrade content, any code written for the Cinemachine 2.x API will likely cease to function without human intervention. Unfortunately, Unity’s automatic script upgrader does not support all of the changes being made to our API.

The minimum Unity Editor version required for Cinemachine 3.0 will be Unity 2022.2.

For a full list of what’s changing, please refer to this doc.

The plan from here
Always note that future plans are subject to change. The following represents our intended release schedule.

Cinemachine 3.0.0-pre.3 is already available in pre-release

  • Unity 2022.2 users will only be able to access CM 3.0 by hand-editing the manifest.json or entering the package name in Package Manager’s Add Package By Name field. In 2023.1, users will be able to access CM 3.0 by enabling pre-release packages, then finding the package in the Package Manager UI.

Cinemachine 3.0 will be the default version of Cinemachine in 2023.2

  • In 2023.2, CM 3.0 will be accessible directly in Package Manager, without having to enable pre-release packages.

Thanks to all of you for your continued support!

22 Likes

Is the API subject to major changes or could we try it on already ?

The API has changed considerably. See the details here: Upgrading a Project from Cinemachine 2.X | Cinemachine | 3.0.1

Sorry I was not clear enough, is the 3.0-pre api subject to upcoming changes or is it stable enough to build upon? It’s allright if bugs are coming in the way.

There are still some changes in the pipe. I would wait a little longer.

2 Likes

Plan on making any walk throughs of the changes?

They gave the doc link https://docs.unity3d.com/Packages/com.unity.cinemachine@3.0/manual/CinemachineUpgradeFrom2.html

We have made a walkthrough video, but I don’t have info on the release date on-hand right now. Keep your eyes on this space.

This is totally fine and is in fact a better way of introducing new features instead of slapping them on top of old ones, maintaining legacy code with systems that does similar things is depressing.
We currently set cinemachine through its Inspector exposed properties, through timeline cinemachine track and on code is just few lines to blend between them. Code wise, is not an issue upgrade to new APIs. Is more of if/when the time comes for us to upgrade to v3, we would like to maintain existing cameras behavior at minimum.
PS: Kudos for v3!

3 Likes

Does it play well with dots?

No, it’s not targeting DOTS.
We do have a DOTS version of Cinemachine in the works, though.

4 Likes

How does this play with post processing? Are things like focus distance exposed so the calculation doesn’t need to be done twice if needed for other effects?

Yes, the calculated focus distance is exposed in the appropriate places

1 Like

I’ve just received word that the video is basically done. Not exactly sure how long it’ll take to get it posted, probably by end of the week.

2 Likes

Awesome! That alone might make me switch, cause I have a whole script that’s designed to try and pass through focus values to post processing. And it’s sometimes hit or miss.

I assume it still instances the volume? I would love a guide on reccomended implementations, later today I’ll post my current scripts for reference.

Yes, CinemachineVolumeSettings still needs to make a Volume under the hood.

Alternatively, CM3 comes with a new extension, CinemachineAutoFocus, dedicated to this. It does not require its own Volume or DoF profile. Rather, it pushes the focus distance directly into Unity’s new focusDistance setting on the Camera, which you can use as you wish. One way to use this is to make your own Volume with DoF settings that uses the Camera’s focusDistance value rather than the profile’s.

Yeah, thats more or less what i do now, but I have this script that has to take the cinemachine info per camera.

using UnityEngine;
using Beautify.Universal;
using Cinemachine.PostFX;
using Cinemachine;
using Sirenix.OdinInspector;

[DisallowMultipleComponent]
[ExecuteAlways]
[SaveDuringPlay]
public class BeautifyFocusCompatibility : CinemachineExtension
{
    public CinemachineVolumeSettings volumeSettings;
    [HideIf("volumeSettings", null)]
    public FocusTarget altFocusTarget = FocusTarget.LookAtTarget;
    [HideIf("volumeSettings", null)]
    public float focusOffset;
    [ShowIf("altFocusTarget", FocusTarget.CustomTarget)]
    public Transform followTarget;
    /// <summary>
    /// Enable this to ignore the current volume configuration, using custom settings can sometimes get better results.
    /// </summary>
    [HideIf("volumeSettings", null)]
    public bool ignoreVolumeSettings = true;

    protected override void OnEnable()
    {
        volumeSettings = this.gameObject.GetComponent(typeof(CinemachineVolumeSettings)) as CinemachineVolumeSettings;
    }

    /// <summary>Apply PostProcessing effects</summary>
    /// <param name="vcam">The virtual camera being processed</param>
    /// <param name="stage">The current pipeline stage</param>
    /// <param name="state">The current virtual camera state</param>
    /// <param name="deltaTime">The current applicable deltaTime</param>
    protected override void PostPipelineStageCallback(CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    {
        // Set the focus after the camera has been fully positioned.
        if (stage == CinemachineCore.Stage.Finalize)
        {
            // Only process if this current camera is active
            if (vcam.VirtualCameraGameObject == this.gameObject)
            {
                //Do not run if instance does not have dof enabled
                if (BeautifySettings.sharedSettings.depthOfField.value)
                {
                    //If volume settings is not null process from that
                    if (volumeSettings != null)
                    {
                        float focusDistance = volumeSettings.m_FocusOffset;
                        if (volumeSettings.m_FocusTracking == CinemachineVolumeSettings.FocusTrackingMode.LookAtTarget)
                            focusDistance += (state.FinalPosition - state.ReferenceLookAt).magnitude;
                        else
                        {
                            Transform focusTarget = null;
                            switch (volumeSettings.m_FocusTracking)
                            {
                                default: break;
                                case CinemachineVolumeSettings.FocusTrackingMode.FollowTarget: focusTarget = VirtualCamera.Follow; break;
                                case CinemachineVolumeSettings.FocusTrackingMode.CustomTarget: focusTarget = volumeSettings.m_FocusTarget; break;
                                case CinemachineVolumeSettings.FocusTrackingMode.Camera: focusDistance = volumeSettings.m_FocusOffset; break;
                            }
                            if (focusTarget != null)
                                focusDistance += (state.FinalPosition - focusTarget.position).magnitude;
                        }
                        GameEventHub.PublishUpdateDistance(Mathf.Max(0, focusDistance));
                    }
                    //If volume settings is null determine if volume settings is desired if not work off custom data, else find the volume settings
                    else if (volumeSettings == null)
                    {
                        if (ignoreVolumeSettings)
                        {
                            float focusDistance = focusOffset;
                            if (altFocusTarget == FocusTarget.LookAtTarget)
                                focusDistance += (state.FinalPosition - state.ReferenceLookAt).magnitude;
                            else
                            {
                                Transform focusTarget = null;
                                switch (altFocusTarget)
                                {
                                    default: break;
                                    case FocusTarget.FollowTarget: focusTarget = VirtualCamera.Follow; break;
                                    case FocusTarget.CustomTarget: focusTarget = followTarget; break;
                                    case FocusTarget.None: focusDistance = focusOffset; break;
                                }
                                if (focusTarget != null)
                                    focusDistance += (state.FinalPosition - focusTarget.position).magnitude;
                            }
                            /*
                            if (BeautifySettings.instance != null)
                            {
                                BeautifySettings.sharedSettings.depthOfFieldDistance.Override(Mathf.Max(0, focusDistance));
                            }
                            */
                            GameEventHub.PublishUpdateDistance(Mathf.Max(0, focusDistance));
                        }
                        else
                        {
                            volumeSettings = this.gameObject.GetComponent(typeof(CinemachineVolumeSettings)) as CinemachineVolumeSettings;
                        }

                    }
                }
            }
        }
    }
}

public enum FocusTarget
{
    None = 0,
    LookAtTarget = 1,
    FollowTarget = 2,
    CustomTarget = 3,
    Camera = 4
}

If this whole process can be simplified that would be fantastic.

Here it is! (I’ll also edit the original post to add it.)

https://www.youtube.com/watch?v=znOii5cz0RU

4 Likes

I’ve just watch the video, and the improvements are fascinating! No hidden gameobject pipeline, better naming, Splines package supporting, GroupComposer → move to Extensions, split screens by channel (not unity layer) … everything is so good!
I appreciate the hard work of the Cinemachine team. Great Job!! Can’t wait to use this in my new projects.

3 Likes

I was just thinking, is it a hard rule for the minimum version, or mostly a “use at your own risk” in earlier version? For instance, right now I’m using the Spline package in 2021 LTS, which looks like one of the reason or the 2022.2 requirement, it does compile and is functional.

Anyway we’ll probably switch the 2022 LTS when it’s realeased, but if we can start to work on in it in the meantime it’d be great.