public override void MutateCameraState(ref CameraState curState, float deltaTime)
        {
            CinemachineTargetGroup targetGroup = this.TargetGroup;

            if (targetGroup == null)
            {
                base.MutateCameraState(ref curState, deltaTime);
                return;
            }
            if (!this.IsValid || !curState.HasLookAt)
            {
                this.m_prevTargetHeight = 0f;
                return;
            }
            curState.ReferenceLookAt = this.GetLookAtPointAndSetTrackedPoint(targetGroup.transform.position);
            Vector3 v         = base.TrackedPoint - curState.RawPosition;
            float   magnitude = v.magnitude;

            if (magnitude < 0.0001f)
            {
                return;
            }
            Vector3 vector      = v.AlmostZero() ? Vector3.forward : v.normalized;
            Bounds  boundingBox = targetGroup.BoundingBox;

            this.m_lastBoundsMatrix = Matrix4x4.TRS(boundingBox.center - vector * boundingBox.extents.magnitude, Quaternion.LookRotation(vector, curState.ReferenceUp), Vector3.one);
            this.m_LastBounds       = targetGroup.GetViewSpaceBoundingBox(this.m_lastBoundsMatrix);
            float   num = this.GetTargetHeight(this.m_LastBounds);
            Vector3 a   = this.m_lastBoundsMatrix.MultiplyPoint3x4(this.m_LastBounds.center);

            if (deltaTime >= 0f)
            {
                float num2 = num - this.m_prevTargetHeight;
                num2 = Damper.Damp(num2, this.m_FrameDamping, deltaTime);
                num  = this.m_prevTargetHeight + num2;
            }
            this.m_prevTargetHeight = num;
            if (!curState.Lens.Orthographic && this.m_AdjustmentMode != CinemachineGroupComposer.AdjustmentMode.ZoomOnly)
            {
                float fieldOfView = curState.Lens.FieldOfView;
                float num3        = num / (2f * Mathf.Tan(fieldOfView * 0.0174532924f / 2f)) + this.m_LastBounds.extents.z;
                num3 = Mathf.Clamp(num3, magnitude - this.m_MaxDollyIn, magnitude + this.m_MaxDollyOut);
                num3 = Mathf.Clamp(num3, this.m_MinimumDistance, this.m_MaximumDistance);
                curState.PositionCorrection += a - vector * num3 - curState.RawPosition;
            }
            if (curState.Lens.Orthographic || this.m_AdjustmentMode != CinemachineGroupComposer.AdjustmentMode.DollyOnly)
            {
                float num4  = (base.TrackedPoint - curState.CorrectedPosition).magnitude - this.m_LastBounds.extents.z;
                float value = 179f;
                if (num4 > 0.0001f)
                {
                    value = 2f * Mathf.Atan(num / (2f * num4)) * 57.29578f;
                }
                LensSettings lens = curState.Lens;
                lens.FieldOfView      = Mathf.Clamp(value, this.m_MinimumFOV, this.m_MaximumFOV);
                lens.OrthographicSize = Mathf.Clamp(num / 2f, this.m_MinimumOrthoSize, this.m_MaximumOrthoSize);
                curState.Lens         = lens;
            }
            base.MutateCameraState(ref curState, deltaTime);
        }
Пример #2
0
        Vector3 ComputeGroupBounds(CinemachineTargetGroup group, ref CameraState curState)
        {
            Vector3 cameraPos = curState.RawPosition;
            Vector3 fwd       = curState.RawOrientation * Vector3.forward;

            // Get the bounding box from camera's direction in view space
            LastBoundsMatrix = Matrix4x4.TRS(cameraPos, curState.RawOrientation, Vector3.one);
            Bounds  b           = group.GetViewSpaceBoundingBox(LastBoundsMatrix);
            Vector3 groupCenter = LastBoundsMatrix.MultiplyPoint3x4(b.center);
            float   boundsDepth = b.extents.z;

            if (!curState.Lens.Orthographic)
            {
                // Parallax might change bounds - refine
                float d = (Quaternion.Inverse(curState.RawOrientation) * (groupCenter - cameraPos)).z;
                cameraPos = groupCenter - fwd * (Mathf.Max(d, boundsDepth) + boundsDepth);

                // Will adjust cameraPos
                b = GetScreenSpaceGroupBoundingBox(group, ref cameraPos, curState.RawOrientation);
                LastBoundsMatrix = Matrix4x4.TRS(cameraPos, curState.RawOrientation, Vector3.one);
                groupCenter      = LastBoundsMatrix.MultiplyPoint3x4(b.center);
            }
            LastBounds = b;
            return(groupCenter - fwd * boundsDepth);
        }
        float AdjustCameraDepthAndLensForGroupFraming(
            CinemachineTargetGroup group, float targetZ, 
            ref CameraState curState, float deltaTime)
        {
            float cameraOffset = 0;

            // Get the bounding box from that POV in view space, and find its height
            Bounds bounds = group.BoundingBox;
            Vector3 fwd = curState.RawOrientation * Vector3.forward;
            m_lastBoundsMatrix = Matrix4x4.TRS(
                    bounds.center - (fwd * bounds.extents.magnitude),
                    curState.RawOrientation, Vector3.one);
            m_LastBounds = group.GetViewSpaceBoundingBox(m_lastBoundsMatrix);
            float targetHeight = GetTargetHeight(m_LastBounds);

            // Apply damping
            if (deltaTime >= 0)
            {
                float delta = targetHeight - m_prevTargetHeight;
                delta = Damper.Damp(delta, m_ZDamping, deltaTime);
                targetHeight = m_prevTargetHeight + delta;
            }
            m_prevTargetHeight = targetHeight;

            // Move the camera
            if (!curState.Lens.Orthographic && m_AdjustmentMode != AdjustmentMode.ZoomOnly)
            {
                // What distance would be needed to get the target height, at the current FOV
                float desiredDistance 
                    = targetHeight / (2f * Mathf.Tan(curState.Lens.FieldOfView * Mathf.Deg2Rad / 2f));

                // target the near surface of the bounding box
                desiredDistance += m_LastBounds.extents.z;

                // Clamp to respect min/max distance settings
                desiredDistance = Mathf.Clamp(
                        desiredDistance, targetZ - m_MaxDollyIn, targetZ + m_MaxDollyOut);
                desiredDistance = Mathf.Clamp(desiredDistance, m_MinimumDistance, m_MaximumDistance);

                // Apply
                cameraOffset += desiredDistance - targetZ;
            }

            // Apply zoom
            if (curState.Lens.Orthographic || m_AdjustmentMode != AdjustmentMode.DollyOnly)
            {
                float nearBoundsDistance = (targetZ + cameraOffset) - m_LastBounds.extents.z;
                float currentFOV = 179;
                if (nearBoundsDistance > Epsilon)
                    currentFOV = 2f * Mathf.Atan(targetHeight / (2 * nearBoundsDistance)) * Mathf.Rad2Deg;

                LensSettings lens = curState.Lens;
                lens.FieldOfView = Mathf.Clamp(currentFOV, m_MinimumFOV, m_MaximumFOV);
                lens.OrthographicSize = Mathf.Clamp(targetHeight / 2, m_MinimumOrthoSize, m_MaximumOrthoSize);
                curState.Lens = lens;
            }
            return -cameraOffset;
        }
Пример #4
0
        private float AdjustCameraDepthAndLensForGroupFraming(CinemachineTargetGroup group, float targetZ, ref CameraState curState, float deltaTime)
        {
            float   num         = 0f;
            Bounds  boundingBox = group.BoundingBox;
            Vector3 a           = curState.RawOrientation * Vector3.forward;

            this.m_lastBoundsMatrix = Matrix4x4.TRS(boundingBox.center - a * boundingBox.extents.magnitude, curState.RawOrientation, Vector3.one);
            this.m_LastBounds       = group.GetViewSpaceBoundingBox(this.m_lastBoundsMatrix);
            float num2 = this.GetTargetHeight(this.m_LastBounds);

            if (deltaTime >= 0f)
            {
                float num3 = num2 - this.m_prevTargetHeight;
                num3 = Damper.Damp(num3, this.m_ZDamping, deltaTime);
                num2 = this.m_prevTargetHeight + num3;
            }
            this.m_prevTargetHeight = num2;
            if (!curState.Lens.Orthographic && this.m_AdjustmentMode != CinemachineFramingTransposer.AdjustmentMode.ZoomOnly)
            {
                float num4 = num2 / (2f * Mathf.Tan(curState.Lens.FieldOfView * 0.0174532924f / 2f));
                num4 += this.m_LastBounds.extents.z;
                num4  = Mathf.Clamp(num4, targetZ - this.m_MaxDollyIn, targetZ + this.m_MaxDollyOut);
                num4  = Mathf.Clamp(num4, this.m_MinimumDistance, this.m_MaximumDistance);
                num  += num4 - targetZ;
            }
            if (curState.Lens.Orthographic || this.m_AdjustmentMode != CinemachineFramingTransposer.AdjustmentMode.DollyOnly)
            {
                float num5  = targetZ + num - this.m_LastBounds.extents.z;
                float value = 179f;
                if (num5 > 0.0001f)
                {
                    value = 2f * Mathf.Atan(num2 / (2f * num5)) * 57.29578f;
                }
                LensSettings lens = curState.Lens;
                lens.FieldOfView      = Mathf.Clamp(value, this.m_MinimumFOV, this.m_MaximumFOV);
                lens.OrthographicSize = Mathf.Clamp(num2 / 2f, this.m_MinimumOrthoSize, this.m_MaximumOrthoSize);
                curState.Lens         = lens;
            }
            return(-num);
        }
Пример #5
0
        /// <summary>Applies the composer rules and orients the camera accordingly</summary>
        /// <param name="curState">The current camera state</param>
        /// <param name="deltaTime">Used for calculating damping.  If less than
        /// zero, then target will snap to the center of the dead zone.</param>
        public override void MutateCameraState(ref CameraState curState, float deltaTime)
        {
            // Can't do anything without a group to look at
            CinemachineTargetGroup group = LookAtTargetGroup;

            if (group == null)
            {
                base.MutateCameraState(ref curState, deltaTime);
                return;
            }

            if (!IsValid || !curState.HasLookAt)
            {
                m_prevFramingDistance = 0;
                m_prevFOV             = 0;
                return;
            }

            bool isOrthographic = curState.Lens.Orthographic;
            bool canMoveCamera  = !isOrthographic && m_AdjustmentMode != AdjustmentMode.ZoomOnly;

            // Get the bounding box from camera's POV in view space
            Vector3        up          = curState.ReferenceUp;
            var            cameraPos   = curState.RawPosition;
            BoundingSphere s           = group.Sphere;
            Vector3        groupCenter = s.position;
            Vector3        fwd         = groupCenter - cameraPos;
            float          d           = fwd.magnitude;

            if (d < Epsilon)
            {
                return;  // navel-gazing, get outa here
            }
            // Approximate looking at the group center
            fwd /= d;
            LastBoundsMatrix = Matrix4x4.TRS(
                cameraPos, Quaternion.LookRotation(fwd, up), Vector3.one);

            // Correction for the actual center
            Bounds b;

            if (isOrthographic)
            {
                b                = group.GetViewSpaceBoundingBox(LastBoundsMatrix);
                groupCenter      = LastBoundsMatrix.MultiplyPoint3x4(b.center);
                fwd              = (groupCenter - cameraPos).normalized;
                LastBoundsMatrix = Matrix4x4.TRS(cameraPos, Quaternion.LookRotation(fwd, up), Vector3.one);
                b                = group.GetViewSpaceBoundingBox(LastBoundsMatrix);
                LastBounds       = b;
            }
            else
            {
                b = GetScreenSpaceGroupBoundingBox(group, LastBoundsMatrix, out fwd);
                LastBoundsMatrix = Matrix4x4.TRS(cameraPos, Quaternion.LookRotation(fwd, up), Vector3.one);
                LastBounds       = b;
                groupCenter      = cameraPos + fwd * b.center.z;
                fwd = (groupCenter - cameraPos).normalized;
            }

            // Adjust bounds for framing size, and get target height
            float boundsDepth  = b.extents.z;
            float targetHeight = GetTargetHeight(b.size / m_GroupFramingSize);

            if (isOrthographic)
            {
                targetHeight = Mathf.Clamp(targetHeight, m_MinimumOrthoSize, m_MaximumOrthoSize);

                // ApplyDamping
                if (deltaTime >= 0)
                {
                    targetHeight = m_prevFOV + Damper.Damp(targetHeight - m_prevFOV, m_FrameDamping, deltaTime);
                }
                m_prevFOV = targetHeight;

                LensSettings lens = curState.Lens;
                lens.OrthographicSize = Mathf.Clamp(targetHeight / 2, m_MinimumOrthoSize, m_MaximumOrthoSize);
                curState.Lens         = lens;
            }
            else
            {
                // Adjust height for perspective - we want the height at the near surface
                float z = b.center.z;
                if (z > boundsDepth)
                {
                    targetHeight = Mathf.Lerp(0, targetHeight, (z - boundsDepth) / z);
                }

                // Move the camera
                if (canMoveCamera)
                {
                    // What distance from near edge would be needed to get the adjusted
                    // target height, at the current FOV
                    float targetDistance = boundsDepth
                                           + targetHeight / (2f * Mathf.Tan(curState.Lens.FieldOfView * Mathf.Deg2Rad / 2f));

                    // Clamp to respect min/max distance settings to the near surface of the bounds
                    targetDistance = Mathf.Clamp(
                        targetDistance, boundsDepth + m_MinimumDistance, boundsDepth + m_MaximumDistance);

                    // Clamp to respect min/max camera movement
                    float targetDelta = targetDistance - Vector3.Distance(curState.RawPosition, groupCenter);
                    targetDelta = Mathf.Clamp(targetDelta, -m_MaxDollyIn, m_MaxDollyOut);

                    // ApplyDamping
                    if (deltaTime >= 0)
                    {
                        float delta = targetDelta - m_prevFramingDistance;
                        delta       = Damper.Damp(delta, m_FrameDamping, deltaTime);
                        targetDelta = m_prevFramingDistance + delta;
                    }
                    m_prevFramingDistance        = targetDelta;
                    curState.PositionCorrection -= fwd * targetDelta;
                    cameraPos -= fwd * targetDelta;
                }

                // Apply zoom
                if (m_AdjustmentMode != AdjustmentMode.DollyOnly)
                {
                    float nearBoundsDistance = (groupCenter - cameraPos).magnitude - boundsDepth;
                    float targetFOV          = 179;
                    if (nearBoundsDistance > Epsilon)
                    {
                        targetFOV = 2f * Mathf.Atan(targetHeight / (2 * nearBoundsDistance)) * Mathf.Rad2Deg;
                    }
                    targetFOV = Mathf.Clamp(targetFOV, m_MinimumFOV, m_MaximumFOV);

                    // ApplyDamping
                    if (deltaTime >= 0 && m_prevFOV != 0)
                    {
                        targetFOV = m_prevFOV + Damper.Damp(targetFOV - m_prevFOV, m_FrameDamping, deltaTime);
                    }
                    m_prevFOV = targetFOV;

                    LensSettings lens = curState.Lens;
                    lens.FieldOfView = targetFOV;
                    curState.Lens    = lens;
                }
            }
            // Now compose normally
            curState.ReferenceLookAt = GetLookAtPointAndSetTrackedPoint(groupCenter);
            base.MutateCameraState(ref curState, deltaTime);
        }
Пример #6
0
        /// <summary>Applies the composer rules and orients the camera accordingly</summary>
        /// <param name="state">The current camera state</param>
        /// <param name="deltaTime">Used for calculating damping.  If less than
        /// zero, then target will snap to the center of the dead zone.</param>
        public override void MutateCameraState(ref CameraState curState, float deltaTime)
        {
            // Can't do anything without a group to look at
            CinemachineTargetGroup group = TargetGroup;

            if (group == null)
            {
                base.MutateCameraState(ref curState, deltaTime);
                return;
            }

            if (!IsValid || !curState.HasLookAt)
            {
                m_prevTargetHeight = 0;
                return;
            }

            // The following line shouldn't be necessary.  You can try enabling it as a
            // last resort if you're getting inexplicable jitter.  That can sometimes come
            // about because the group's target members are not animated in a consistent way.
            //group.LateUpdate(); // Make sure the group's position is fully updated.

            curState.ReferenceLookAt = group.transform.position;
            Vector3 lookAtPosition  = GetTrackedPoint(curState.ReferenceLookAt);
            Vector3 currentOffset   = lookAtPosition - curState.RawPosition;
            float   currentDistance = currentOffset.magnitude;

            if (currentDistance < Epsilon)
            {
                return;  // navel-gazing, get outa here
            }
            //UnityEngine.Profiling.Profiler.BeginSample("CinemachineGroupComposer.MutateCameraState");

            // Get the camera axis
            Vector3 fwd = currentOffset.AlmostZero() ? Vector3.forward : currentOffset.normalized;

            // Get the bounding box from that POV in view space, and find its width
            Bounds bounds = group.BoundingBox;

            m_lastBoundsMatrix = Matrix4x4.TRS(
                bounds.center - (fwd * bounds.extents.magnitude),
                Quaternion.LookRotation(fwd, curState.ReferenceUp), Vector3.one);
            m_LastBounds = group.GetViewSpaceBoundingBox(m_lastBoundsMatrix);
            float   targetHeight = GetTargetHeight(m_LastBounds);
            Vector3 targetPos    = m_lastBoundsMatrix.MultiplyPoint3x4(m_LastBounds.center);

            // Apply damping
            if (deltaTime >= 0)
            {
                float delta = targetHeight - m_prevTargetHeight;
                delta        = Damper.Damp(delta, m_FrameDamping, deltaTime);
                targetHeight = m_prevTargetHeight + delta;
            }
            m_prevTargetHeight = targetHeight;

            // Move the camera
            if (!curState.Lens.Orthographic && m_AdjustmentMode != AdjustmentMode.ZoomOnly)
            {
                // What distance would be needed to get the target height, at the current FOV
                float currentFOV     = curState.Lens.FieldOfView;
                float targetDistance = targetHeight / (2f * Mathf.Tan(currentFOV * Mathf.Deg2Rad / 2f));

                // target the near surface of the bounding box
                float cameraDistance = targetDistance + m_LastBounds.extents.z;

                // Clamp to respect min/max distance settings
                cameraDistance = Mathf.Clamp(
                    cameraDistance, currentDistance - m_MaxDollyIn, currentDistance + m_MaxDollyOut);
                cameraDistance = Mathf.Clamp(cameraDistance, m_MinimumDistance, m_MaximumDistance);

                // Apply
                curState.PositionCorrection += targetPos - fwd * cameraDistance - curState.RawPosition;
            }

            // Apply zoom
            if (curState.Lens.Orthographic || m_AdjustmentMode != AdjustmentMode.DollyOnly)
            {
                float nearBoundsDistance = (lookAtPosition - curState.CorrectedPosition).magnitude
                                           - m_LastBounds.extents.z;
                float currentFOV = 179;
                if (nearBoundsDistance > Epsilon)
                {
                    currentFOV = 2f * Mathf.Atan(targetHeight / (2 * nearBoundsDistance)) * Mathf.Rad2Deg;
                }

                LensSettings lens = curState.Lens;
                lens.FieldOfView      = Mathf.Clamp(currentFOV, m_MinimumFOV, m_MaximumFOV);
                lens.OrthographicSize = Mathf.Clamp(targetHeight / 2, m_MinimumOrthoSize, m_MaximumOrthoSize);
                curState.Lens         = lens;
            }

            // Now compose normally
            base.MutateCameraState(ref curState, deltaTime);
            //UnityEngine.Profiling.Profiler.EndSample();
        }
Пример #7
0
        Vector3 AdjustCameraPositionAndLensForGroupFraming(
            CinemachineTargetGroup group, float initialZ,
            ref CameraState curState, float deltaTime)
        {
            Vector3 cameraOffset = Vector3.zero;

            bool canMoveCameraInZ
                = !curState.Lens.Orthographic &&
                  m_AdjustmentMode != AdjustmentMode.ZoomOnly;

            // Work in camera-local space
            Vector3 fwd = curState.RawOrientation * Vector3.forward;
            Vector3 cameraWorldStartPos = TrackedPoint - (fwd * initialZ);

            LastBoundsMatrix = Matrix4x4.TRS(cameraWorldStartPos, curState.RawOrientation, Vector3.one);

            // Get the bounding box from camera's direction in view space
            Bounds b = group.GetViewSpaceBoundingBox(LastBoundsMatrix);

            LastBounds = b;

            // Recenter the camera in x-y, don't touch the depth
            cameraOffset   = b.center;
            cameraOffset.z = 0;

            float firstApproxCameraOffsetZ = 0;

            if (!curState.Lens.Orthographic)
            {
                // Now get a more refined bounding box in screen space
                if (canMoveCameraInZ)
                {
                    float newZ = GetPositionForNearBounds(
                        b, GetTargetHeight(b), curState.Lens.FieldOfView, false);
                    firstApproxCameraOffsetZ = Mathf.Clamp(newZ, -m_MaxDollyOut, m_MaxDollyIn);
                    cameraOffset.z           = firstApproxCameraOffsetZ;
                }
                Vector3 worldObserverPos = LastBoundsMatrix.MultiplyPoint3x4(cameraOffset);
                Vector3 localPosAdustmentXY;
                b = GetScreenSpaceGroupBoundingBox(
                    group, ref worldObserverPos, curState.RawOrientation, out localPosAdustmentXY);
                cameraOffset += localPosAdustmentXY;
                // worldObserverPos has been adjusted
                LastBoundsMatrix = Matrix4x4.TRS(worldObserverPos, curState.RawOrientation, Vector3.one);
                LastBounds       = b;
            }
            // Bring it back to local space
            b.center      += cameraOffset;
            cameraOffset.z = 0;

            // Adjust bounds for framing size
            Vector3 extents = b.extents / m_GroupFramingSize;

            extents.z = Mathf.Min(b.extents.z, extents.z);
            b.extents = extents;

            // Apply damping
            float targetHeight = GetTargetHeight(b);

            if (deltaTime >= 0)
            {
                float delta = targetHeight - m_prevTargetHeight;
                delta        = Damper.Damp(delta, m_ZDamping, deltaTime);
                targetHeight = m_prevTargetHeight + delta;
            }
            m_prevTargetHeight = targetHeight;

            // Move the camera in Z
            if (canMoveCameraInZ)
            {
                float newZ = GetPositionForNearBounds(
                    new Bounds(b.center - new Vector3(0, 0, firstApproxCameraOffsetZ), b.size),
                    targetHeight, curState.Lens.FieldOfView, true);
                newZ          += firstApproxCameraOffsetZ;
                cameraOffset.z = Mathf.Clamp(newZ, -m_MaxDollyOut, m_MaxDollyIn);
            }

            // Apply zoom
            if (curState.Lens.Orthographic || m_AdjustmentMode != AdjustmentMode.DollyOnly)
            {
                float targetDistance = b.center.z - cameraOffset.z;
                float currentFOV     = 179;
                if (targetDistance > Epsilon)
                {
                    currentFOV = 2f * Mathf.Atan(targetHeight / (2 * targetDistance)) * Mathf.Rad2Deg;
                }

                LensSettings lens = curState.Lens;
                lens.FieldOfView      = Mathf.Clamp(currentFOV, m_MinimumFOV, m_MaximumFOV);
                lens.OrthographicSize = Mathf.Clamp(targetHeight / 2, m_MinimumOrthoSize, m_MaximumOrthoSize);
                curState.Lens         = lens;
            }

            return(cameraOffset);
        }
        /// <summary>Applies the composer rules and orients the camera accordingly</summary>
        /// <param name="state">The current camera state</param>
        /// <param name="statePrevFrame">The camera state on the previous frame (unused)</param>
        /// <param name="deltaTime">Used for calculating damping.  If less than
        /// or equal to zero, then target will snap to the center of the dead zone.</param>
        /// <returns>curState with RawOrientation applied</returns>
        public override CameraState MutateCameraState(
            CameraState state, CameraState statePrevFrame, float deltaTime)
        {
            if (!IsValid || !state.HasLookAt)
            {
                return(state);
            }

            // Can't do anything without a group to look at
            CinemachineTargetGroup group = VirtualCamera.LookAt.GetComponent <CinemachineTargetGroup>();

            if (group == null)
            {
                return(base.MutateCameraState(state, statePrevFrame, deltaTime));
            }

            group.Update(); // Make sure the group's position is fully updated.
            state.ReferenceLookAt = group.transform.position;
            Vector3 lookAtPosition  = GetTrackedPoint(state.ReferenceLookAt);
            Vector3 currentOffset   = lookAtPosition - state.CorrectedPosition;
            float   currentDistance = currentOffset.magnitude;

            if (currentDistance < UnityVectorExtensions.Epsilon)
            {
                return(state);  // navel-gazing, get outa here
            }
            // Get the camera axis
            Vector3 fwd = currentOffset.AlmostZero() ? Vector3.forward : currentOffset.normalized;

            // Get the bounding box from that POV in view space, and find its width
            Bounds bounds = group.BoundingBox;

            m_lastBoundsMatrix = Matrix4x4.TRS(
                bounds.center - (fwd * bounds.extents.magnitude),
                Quaternion.LookRotation(fwd, state.ReferenceUp), Vector3.one);
            m_LastBounds = group.GetViewSpaceBoundingBox(m_lastBoundsMatrix);
            float   targetHeight = GetTargetHeight(m_LastBounds);
            Vector3 targetPos    = m_lastBoundsMatrix.MultiplyPoint3x4(m_LastBounds.center);

            // Apply damping
            if (deltaTime > 0 && m_FrameDamping > 0)
            {
                float delta = targetHeight - m_prevTargetHeight;
                delta       *= deltaTime / Mathf.Max(m_FrameDamping * kHumanReadableDampingScale, deltaTime);
                targetHeight = m_prevTargetHeight + delta;
            }
            m_prevTargetHeight = targetHeight;

            // Move the camera
            if (!state.Lens.Orthographic && m_AdjustmentMode != AdjustmentMode.ZoomOnly)
            {
                // What distance would be needed to get the target height, at the current FOV
                float currentFOV     = state.Lens.FieldOfView;
                float targetDistance = targetHeight / (2f * Mathf.Tan(currentFOV * Mathf.Deg2Rad / 2f));

                // target the near surface of the bounding box
                float cameraDistance = targetDistance + m_LastBounds.extents.z;

                // Clamp to respect min/max distance settings
                cameraDistance = Mathf.Clamp(
                    cameraDistance, currentDistance - m_MaxDollyIn, currentDistance + m_MaxDollyOut);
                cameraDistance = Mathf.Clamp(cameraDistance, m_MinimumDistance, m_MaximumDistance);

                // Apply
                state.PositionCorrection += targetPos - fwd * cameraDistance - state.CorrectedPosition;
            }

            // Apply zoom
            if (state.Lens.Orthographic || m_AdjustmentMode != AdjustmentMode.DollyOnly)
            {
                float nearBoundsDistance = (lookAtPosition - state.CorrectedPosition).magnitude
                                           - m_LastBounds.extents.z;
                float currentFOV = 179;
                if (nearBoundsDistance > UnityVectorExtensions.Epsilon)
                {
                    currentFOV = 2f * Mathf.Atan(targetHeight / (2 * nearBoundsDistance)) * Mathf.Rad2Deg;
                }

                LensSettings lens = state.Lens;
                lens.FieldOfView      = Mathf.Clamp(currentFOV, m_MinimumFOV, m_MaximumFOV);
                lens.OrthographicSize = targetHeight / 2;
                state.Lens            = lens;
            }

            // Now compose normally
            return(base.MutateCameraState(state, statePrevFrame, deltaTime));
        }
Пример #9
0
        /// <summary>Applies the composer rules and orients the camera accordingly</summary>
        /// <param name="curState">The current camera state</param>
        /// <param name="deltaTime">Used for calculating damping.  If less than
        /// zero, then target will snap to the center of the dead zone.</param>
        public override void MutateCameraState(ref CameraState curState, float deltaTime)
        {
            // Can't do anything without a group to look at
            CinemachineTargetGroup group = LookAtTargetGroup;

            if (group == null)
            {
                base.MutateCameraState(ref curState, deltaTime);
                return;
            }

            if (!IsValid || !curState.HasLookAt)
            {
                m_prevTargetHeight = 0;
                m_prevCameraOffset = Vector3.zero;
                return;
            }

            bool canMoveCamera
                = !curState.Lens.Orthographic && m_AdjustmentMode != AdjustmentMode.ZoomOnly;

            // Get the bounding box from camera's POV in view space
            Vector3        observerPosition = curState.RawPosition;
            BoundingSphere s               = group.Sphere;
            Vector3        groupCenter     = s.position;
            Vector3        currentOffset   = groupCenter - observerPosition;
            float          currentDistance = currentOffset.magnitude;

            if (currentDistance < Epsilon)
            {
                return;  // navel-gazing, get outa here
            }
            Vector3 fwd = currentOffset / currentDistance;

            LastBoundsMatrix = Matrix4x4.TRS(observerPosition,
                                             Quaternion.LookRotation(fwd, curState.ReferenceUp), Vector3.one);
            Bounds b;

            if (curState.Lens.Orthographic)
            {
                b = group.GetViewSpaceBoundingBox(LastBoundsMatrix);
                Vector3 sizeDelta = new Vector3(b.center.x, b.center.y, 0);
                b.size    += sizeDelta.Abs() * 2;
                b.center   = new Vector3(0, 0, b.center.z);
                LastBounds = b;
            }
            else
            {
                if (canMoveCamera)
                {
                    // Get an upper bound on the distance
                    b           = group.GetViewSpaceBoundingBox(LastBoundsMatrix);
                    groupCenter = LastBoundsMatrix.MultiplyPoint3x4(b.center);

                    // Now try to get closer
                    float distance = GetTargetHeight(b)
                                     / (2f * Mathf.Tan(curState.Lens.FieldOfView * Mathf.Deg2Rad / 2f));
                    Vector3 nearCenter = b.center; nearCenter.z -= b.extents.z;
                    nearCenter = LastBoundsMatrix.MultiplyPoint3x4(nearCenter);
                    Vector3 newFwd = (groupCenter - nearCenter).normalized;
                    if (!newFwd.AlmostZero())
                    {
                        fwd = newFwd;
                    }
                    observerPosition = nearCenter - (fwd * distance);
                    LastBoundsMatrix = Matrix4x4.TRS(observerPosition,
                                                     Quaternion.LookRotation(fwd, curState.ReferenceUp), Vector3.one);
                }

                b = GetScreenSpaceGroupBoundingBox(group, LastBoundsMatrix, out fwd);
                LastBoundsMatrix = Matrix4x4.TRS(observerPosition,
                                                 Quaternion.LookRotation(fwd, curState.ReferenceUp), Vector3.one);
                LastBounds      = b;
                groupCenter     = LastBoundsMatrix.MultiplyPoint3x4(b.center);
                currentOffset   = groupCenter - curState.RawPosition;
                currentDistance = currentOffset.magnitude;
            }

            // Adjust bounds for framing size
            Vector3 extents = b.extents / m_GroupFramingSize;

            extents.z = Mathf.Min(b.extents.z, extents.z);
            b.extents = extents;

            // Apply damping
            float targetHeight = GetTargetHeight(b);

            if (deltaTime >= 0)
            {
                float delta = targetHeight - m_prevTargetHeight;
                delta        = Damper.Damp(delta, m_FrameDamping, deltaTime);
                targetHeight = m_prevTargetHeight + delta;
            }
            m_prevTargetHeight = targetHeight;

            // Move the camera
            if (canMoveCamera)
            {
                // What distance would be needed to get the target height, at the current FOV
                float depth            = b.extents.z;
                float d                = (groupCenter - observerPosition).magnitude;
                float nearTargetHeight = targetHeight * (d - depth) / d;
                float targetDistance   = nearTargetHeight
                                         / (2f * Mathf.Tan(curState.Lens.FieldOfView * Mathf.Deg2Rad / 2f));

                // Clamp to respect min/max distance settings to the near surface of the bounds
                float cameraDistance = targetDistance;
                cameraDistance  = Mathf.Clamp(cameraDistance, currentDistance - m_MaxDollyIn, currentDistance + m_MaxDollyOut);
                cameraDistance -= depth;
                cameraDistance  = Mathf.Clamp(cameraDistance, m_MinimumDistance, m_MaximumDistance);
                cameraDistance += depth;

                // Apply
                Vector3 newCamOffset
                    = (groupCenter - (fwd * (cameraDistance + depth))) - curState.RawPosition;
                if (deltaTime >= 0)
                {
                    Vector3 delta = newCamOffset - m_prevCameraOffset;
                    delta        = Damper.Damp(delta, m_FrameDamping, deltaTime);
                    newCamOffset = m_prevCameraOffset + delta;
                }
                m_prevCameraOffset           = newCamOffset;
                curState.PositionCorrection += newCamOffset;
            }

            // Apply zoom
            if (curState.Lens.Orthographic || m_AdjustmentMode != AdjustmentMode.DollyOnly)
            {
                float nearBoundsDistance = (groupCenter - curState.CorrectedPosition).magnitude;
                float currentFOV         = 179;
                if (nearBoundsDistance > Epsilon)
                {
                    currentFOV = 2f * Mathf.Atan(targetHeight / (2 * nearBoundsDistance)) * Mathf.Rad2Deg;
                }

                LensSettings lens = curState.Lens;
                lens.FieldOfView      = Mathf.Clamp(currentFOV, m_MinimumFOV, m_MaximumFOV);
                lens.OrthographicSize = Mathf.Clamp(targetHeight / 2, m_MinimumOrthoSize, m_MaximumOrthoSize);
                curState.Lens         = lens;
            }

            // Now compose normally
            curState.ReferenceLookAt = GetLookAtPointAndSetTrackedPoint(groupCenter);
            base.MutateCameraState(ref curState, deltaTime);
        }