/// <summary>Positions the virtual camera according to the transposer rules.</summary> /// <param name="curState">The current camera state</param> /// <param name="deltaTime">Used for damping. If less that 0, no damping is done.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { // Init previous frame state info if (deltaTime < 0) { m_PreviousPathPosition = m_PathPosition; m_PreviousCameraPosition = curState.RawPosition; } if (!IsValid) { return; } //UnityEngine.Profiling.Profiler.BeginSample("CinemachineTrackedDolly.MutateCameraState"); // Get the new ideal path base position if (m_AutoDolly.m_Enabled && FollowTarget != null) { float prevPos = m_PreviousPathPosition; if (m_PositionUnits == CinemachinePathBase.PositionUnits.Distance) { prevPos = m_Path.GetPathPositionFromDistance(prevPos); } // This works in path units m_PathPosition = m_Path.FindClosestPoint( FollowTarget.transform.position, Mathf.FloorToInt(prevPos), (deltaTime < 0 || m_AutoDolly.m_SearchRadius <= 0) ? -1 : m_AutoDolly.m_SearchRadius, m_AutoDolly.m_SearchResolution); if (m_PositionUnits == CinemachinePathBase.PositionUnits.Distance) { m_PathPosition = m_Path.GetPathDistanceFromPosition(m_PathPosition); } // Apply the path position offset m_PathPosition += m_AutoDolly.m_PositionOffset; } float newPathPosition = m_PathPosition; if (deltaTime >= 0) { // Normalize previous position to find the shortest path float maxUnit = m_Path.MaxUnit(m_PositionUnits); if (maxUnit > 0) { float prev = m_Path.NormalizeUnit(m_PreviousPathPosition, m_PositionUnits); float next = m_Path.NormalizeUnit(newPathPosition, m_PositionUnits); if (m_Path.Looped && Mathf.Abs(next - prev) > maxUnit / 2) { if (next > prev) { prev += maxUnit; } else { prev -= maxUnit; } } m_PreviousPathPosition = prev; newPathPosition = next; } // Apply damping along the path direction float offset = m_PreviousPathPosition - newPathPosition; offset = Damper.Damp(offset, m_ZDamping, deltaTime); newPathPosition = m_PreviousPathPosition - offset; } m_PreviousPathPosition = newPathPosition; Quaternion newPathOrientation = m_Path.EvaluateOrientationAtUnit(newPathPosition, m_PositionUnits); // Apply the offset to get the new camera position Vector3 newCameraPos = m_Path.EvaluatePositionAtUnit(newPathPosition, m_PositionUnits); Vector3 offsetX = newPathOrientation * Vector3.right; Vector3 offsetY = newPathOrientation * Vector3.up; Vector3 offsetZ = newPathOrientation * Vector3.forward; newCameraPos += m_PathOffset.x * offsetX; newCameraPos += m_PathOffset.y * offsetY; newCameraPos += m_PathOffset.z * offsetZ; // Apply damping to the remaining directions if (deltaTime >= 0) { Vector3 currentCameraPos = m_PreviousCameraPosition; Vector3 delta = (currentCameraPos - newCameraPos); Vector3 delta1 = Vector3.Dot(delta, offsetY) * offsetY; Vector3 delta0 = delta - delta1; delta0 = Damper.Damp(delta0, m_XDamping, deltaTime); delta1 = Damper.Damp(delta1, m_YDamping, deltaTime); newCameraPos = currentCameraPos - (delta0 + delta1); } curState.RawPosition = m_PreviousCameraPosition = newCameraPos; // Set the orientation and up Quaternion newOrientation = GetTargetOrientationAtPathPoint(newPathOrientation, curState.ReferenceUp); if (deltaTime < 0) { m_PreviousOrientation = newOrientation; } else { if (deltaTime >= 0) { Vector3 relative = (Quaternion.Inverse(m_PreviousOrientation) * newOrientation).eulerAngles; for (int i = 0; i < 3; ++i) { if (relative[i] > 180) { relative[i] -= 360; } } relative = Damper.Damp(relative, AngularDamping, deltaTime); newOrientation = m_PreviousOrientation * Quaternion.Euler(relative); } m_PreviousOrientation = newOrientation; } curState.RawOrientation = newOrientation; curState.ReferenceUp = curState.RawOrientation * Vector3.up; //UnityEngine.Profiling.Profiler.EndSample(); }