State Driven Camera (SDC) apparent regression in 2.4.0

Hi,
I’m heavily relying on StateDrivenCamera, however in a scene setup that was working perfectly well previous camera don’t get deactivated when changing the state. I tried debugging internally (ChooseCurrentCamera and InternalUpdateCameraState) and I don’t see how the code deactivate previous camera

CM_MainLoop should be deactivated here. Going back and force state calls InternalUpdateCameraState but don’t disable either of the two

5404185--548619--upload_2020-1-24_12-39-26.png

5404092--548574--upload_2020-1-24_12-0-23.png

5404092--548580--upload_2020-1-24_12-0-56.png

[Edit 1]:
I steped in :
public override void OnTransitionFromCamera(
ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)

fromCam is CM_MainLoop as expected, “this.” is CM_CollectionCamera. However no deactivation here. I also tried putting steps on AddActiveCamera and RemoveActiveCamera it never steps in

So I’m looking at previous State Driven Camera code before the rewrite :

You were iterating through all cams and deactivating those not being the “best” (Not sur it was a good practice, letting the transition do the deactivation feels indeed better)

  if (m_ChildCameras != null)
            {
                for (int i = 0; i < m_ChildCameras.Length; ++i)
                {
                    CinemachineVirtualCameraBase vcam  = m_ChildCameras[i];
                    if (vcam != null)
                    {
                        bool enableChild = m_EnableAllChildCameras || vcam == best;
                        if (enableChild != vcam.VirtualCameraGameObject.activeInHierarchy)
                        {
                            vcam.gameObject.SetActive(enableChild);
                            if (enableChild)
                                CinemachineCore.Instance.UpdateVirtualCamera(vcam, worldUp, deltaTime);
                        }
                    }
                }
            }

I implemented this myself previously and it was VERY useful, I think I can manage it with an extension however so it can be extended to any type of VCam.

 if (mActiveBlend != null)
            {
                mActiveBlend.UpdateCameraState(worldUp, deltaTime);
                m_State = mActiveBlend.State;
            }
            else if (LiveChild != null)
            {
                if (m_InheritChildPriority)
                {
                    Priority = LiveChild.Priority;
                }
                m_State = LiveChild.State;
            }

5404185--548619--upload_2020-1-24_12-39-26.png

It’s pretty rough but here is an extension that handles child priority inheritance, I’m pretty sure it could be included in the package if you feel so. Also there is a small fix for state driven camera not deactivating children.

It seems to work on my project (there is a couple of extension method, use builtin “as” keywork and ! operator for the bool)

    public class CinemachineInheritChildPriority : CinemachineExtension, IHasUpdate
    {
        [Tooltip("If recursive retrieve all childs in hierarchy otherwise only direct childs")]
        public bool Recursive = false;

        [Tooltip("Set childs list to be updated at each frame instead of awake")]
        public bool AlwayUpdateChildList = false;
        private List<CinemachineVirtualCameraBase> _childs;
        private CinemachineVirtualCameraBase _cinemachineCameraRoot;

        protected override void Awake()
        {
            base.Awake();
            UpdateChildren();
            _cinemachineCameraRoot = GetComponent<CinemachineVirtualCameraBase>();
        }
        private void UpdateChildren()
        {
            var childs = GetComponentsInChildren<CinemachineVirtualCameraBase>(includeInactive: true)
                //Do not take root object as child
                .Where(c => c.gameObject != gameObject);
            _childs = (Recursive ? childs.Where(c => c.gameObject.transform.parent.gameObject == gameObject) : childs).ToList();
        }

        protected override void PostPipelineStageCallback(CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
        {
            var isNotRootCamera = ReferenceEquals(vcam.gameObject, gameObject).IsFalse();

            //BUG Dirty state driven camera fix
            if (isNotRootCamera)
            {
                _cinemachineCameraRoot
                    .AsOptional<CinemachineStateDrivenCamera>()
                    .IfPresent(sdc =>
                    {
                        if (ReferenceEquals(vcam, sdc.LiveChild)) return;
                        vcam.gameObject.SetActive(false);
                    });
            }

            //only apply on root camera
            if ( isNotRootCamera ) return;
        
            var priority = _childs.Where(c => c.isActiveAndEnabled)
                .OrderByDescending(c => c.Priority).Select(c => c.Priority)
                .FallbackIfEmpty(int.MinValue)
                .First();
            if(priority == int.MinValue)return;
            vcam.Priority = priority;
        }

        public void Update()
        {
            if(AlwayUpdateChildList) UpdateChildren();
        }
    }