/// <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 0 or less, no damping is done.</param> public 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 && VirtualCamera.Follow != null) { float prevPos = m_PreviousPathPosition; if (m_PositionUnits == CinemachinePathBase.PositionUnits.Distance) { prevPos = m_Path.GetPathPositionFromDistance(prevPos); } m_PathPosition = m_Path.FindClosestPoint( VirtualCamera.Follow.transform.position, Mathf.FloorToInt(prevPos), (deltaTime <= 0 || m_AutoDolly.m_SearchRadius <= 0) ? -1 : m_AutoDolly.m_SearchRadius, m_AutoDolly.m_StepsPerSegment); 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; if (Mathf.Abs(offset) > UnityVectorExtensions.Epsilon) { offset *= deltaTime / Mathf.Max(m_ZDamping * kDampingScale, 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; delta = delta0 * deltaTime / Mathf.Max(m_XDamping * kDampingScale, deltaTime) + delta1 * deltaTime / Mathf.Max(m_YDamping * kDampingScale, deltaTime); newCameraPos = currentCameraPos - delta; } 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; Vector3 damping = AngularDamping; for (int i = 0; i < 3; ++i) { if (relative[i] > 180) { relative[i] -= 360; } if (Mathf.Abs(relative[i]) > UnityVectorExtensions.Epsilon) { relative[i] *= deltaTime / Mathf.Max(damping[i], deltaTime); } } newOrientation = m_PreviousOrientation * Quaternion.Euler(relative); } m_PreviousOrientation = newOrientation; } curState.RawOrientation = newOrientation; curState.ReferenceUp = curState.RawOrientation * Vector3.up; //UnityEngine.Profiling.Profiler.EndSample(); }
/// <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 0 or less, no damping is done.</param> public 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; } // Get the new ideal path base position if (m_AutoDolly.m_Enabled && VirtualCamera.Follow != null) { float prevPos = m_PreviousPathPosition; if (m_PositionUnits == CinemachinePathBase.PositionUnits.Distance) { prevPos = m_Path.GetPathPositionFromDistance(prevPos); } m_PathPosition = m_Path.FindClosestPoint( VirtualCamera.Follow.transform.position, Mathf.FloorToInt(prevPos), (deltaTime <= 0 || m_AutoDolly.m_SearchRadius <= 0) ? -1 : m_AutoDolly.m_SearchRadius, m_AutoDolly.m_StepsPerSegment); if (m_PositionUnits == CinemachinePathBase.PositionUnits.Distance) { m_PathPosition = m_Path.GetPathDistanceFromPosition(m_PathPosition); } } 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; if (Mathf.Abs(offset) > UnityVectorExtensions.Epsilon) { offset *= deltaTime / Mathf.Max(m_ZDamping * kDampingScale, 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[] offsetDir = new Vector3[3]; offsetDir[2] = newPathOrientation * Vector3.forward; offsetDir[1] = newPathOrientation * Vector3.up; offsetDir[0] = Vector3.Cross(offsetDir[1], offsetDir[2]); for (int i = 0; i < 3; ++i) { newCameraPos += m_PathOffset[i] * offsetDir[i]; } // Apply damping to the remaining directions if (deltaTime > 0) { Vector3 currentCameraPos = m_PreviousCameraPosition; Vector3 delta = (currentCameraPos - newCameraPos); Vector3 delta1 = Vector3.Dot(delta, offsetDir[1]) * offsetDir[1]; Vector3 delta0 = delta - delta1; delta = delta0 * deltaTime / Mathf.Max(m_XDamping * kDampingScale, deltaTime) + delta1 * deltaTime / Mathf.Max(m_YDamping * kDampingScale, deltaTime); newCameraPos = currentCameraPos - delta; } curState.RawPosition = m_PreviousCameraPosition = newCameraPos; // Set the up switch (m_CameraUp) { default: case CameraUpMode.World: break; case CameraUpMode.Path: curState.ReferenceUp = newPathOrientation * Vector3.up; curState.RawOrientation = newPathOrientation; break; case CameraUpMode.PathNoRoll: curState.RawOrientation = Quaternion.LookRotation( newPathOrientation * Vector3.forward, Vector3.up); curState.ReferenceUp = curState.RawOrientation * Vector3.up; break; case CameraUpMode.FollowTarget: if (VirtualCamera.Follow != null) { curState.RawOrientation = VirtualCamera.Follow.rotation; curState.ReferenceUp = curState.RawOrientation * Vector3.up; } break; case CameraUpMode.FollowTargetNoRoll: if (VirtualCamera.Follow != null) { curState.RawOrientation = Quaternion.LookRotation( VirtualCamera.Follow.rotation * Vector3.forward, Vector3.up); curState.ReferenceUp = curState.RawOrientation * Vector3.up; } break; } }