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); }
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; }
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); }
/// <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); }
/// <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(); }
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)); }
/// <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); }