/// <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 than 0, no damping is done.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { InitPrevFrameStateInfo(ref curState, deltaTime); // Update the heading if (FollowTarget != PreviousTarget) { PreviousTarget = FollowTarget; mTargetRigidBody = (PreviousTarget == null) ? null : PreviousTarget.GetComponent <Rigidbody>(); mLastTargetPosition = (PreviousTarget == null) ? Vector3.zero : PreviousTarget.position; mHeadingTracker = null; } LastHeading = HeadingUpdater(this, deltaTime, curState.ReferenceUp); float heading = LastHeading; if (IsValid) { // Calculate the heading if (m_BindingMode != BindingMode.SimpleFollowWithWorldUp) { heading += m_Heading.m_Bias; } Quaternion headingRot = Quaternion.AngleAxis(heading, Vector3.up); Vector3 rawOffset = EffectiveOffset; Vector3 offset = headingRot * rawOffset; // Track the target, with damping TrackTarget(deltaTime, curState.ReferenceUp, offset, out Vector3 pos, out Quaternion orient); // Place the camera offset = orient * offset; curState.ReferenceUp = orient * Vector3.up; // Respect minimum target distance on XZ plane var targetPosition = FollowTargetPosition; pos += GetOffsetForMinimumTargetDistance( pos, offset, curState.RawOrientation * Vector3.forward, curState.ReferenceUp, targetPosition); curState.RawPosition = pos + offset; if (deltaTime >= 0 && VirtualCamera.PreviousStateIsValid) { var lookAt = targetPosition; if (LookAtTarget != null) { lookAt = LookAtTargetPosition; } var dir0 = mLastCameraPosition - lookAt; var dir1 = curState.RawPosition - lookAt; if (dir0.sqrMagnitude > 0.01f && dir1.sqrMagnitude > 0.01f) { curState.PositionDampingBypass = UnityVectorExtensions.SafeFromToRotation( dir0, dir1, curState.ReferenceUp).eulerAngles; } } mLastTargetPosition = targetPosition; mLastCameraPosition = curState.RawPosition; } }
/// <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 override void MutateCameraState(ref CameraState curState, float deltaTime) { //UnityEngine.Profiling.Profiler.BeginSample("CinemachineOrbitalTransposer.MutateCameraState"); InitPrevFrameStateInfo(ref curState, deltaTime); // Update the heading if (VirtualCamera.Follow != PreviousTarget) { PreviousTarget = VirtualCamera.Follow; mTargetRigidBody = (PreviousTarget == null) ? null : PreviousTarget.GetComponent <Rigidbody>(); mLastTargetPosition = (PreviousTarget == null) ? Vector3.zero : PreviousTarget.position; mHeadingTracker = null; } if (!m_HeadingIsSlave) { UpdateHeading(deltaTime, curState.ReferenceUp); } if (IsValid) { mLastTargetPosition = VirtualCamera.Follow.position; // Place the camera Quaternion targetOrientation = GetReferenceOrientation(curState.ReferenceUp); float heading = m_XAxis.Value + m_Heading.m_HeadingBias; targetOrientation = targetOrientation * Quaternion.AngleAxis(heading, Vector3.up); DoTracking(ref curState, deltaTime, targetOrientation, EffectiveOffset); } //UnityEngine.Profiling.Profiler.EndSample(); }
// Make sure this is calld only once per frame private float GetTargetHeading( float currentHeading, Quaternion targetOrientation, float deltaTime) { if (VirtualCamera.Follow == null) { return(currentHeading); } if (m_Heading.m_HeadingDefinition == Heading.HeadingDefinition.Velocity && mTargetRigidBody == null) { Debug.Log(string.Format( "Attempted to use HeadingDerivationMode.Velocity to calculate heading for {0}. No RigidBody was present on '{1}'. Defaulting to position delta", GetFullName(VirtualCamera.VirtualCameraGameObject), VirtualCamera.Follow)); m_Heading.m_HeadingDefinition = Heading.HeadingDefinition.PositionDelta; } Vector3 velocity = Vector3.zero; switch (m_Heading.m_HeadingDefinition) { case Heading.HeadingDefinition.PositionDelta: velocity = VirtualCamera.Follow.position - mLastTargetPosition; break; case Heading.HeadingDefinition.Velocity: velocity = mTargetRigidBody.velocity; break; default: case Heading.HeadingDefinition.TargetForward: case Heading.HeadingDefinition.WorldForward: return(0); } // Process the velocity and derive the heading from it. int filterSize = m_Heading.m_VelocityFilterStrength * 5; if (mHeadingTracker == null || mHeadingTracker.FilterSize != filterSize) { mHeadingTracker = new HeadingTracker(filterSize); } mHeadingTracker.DecayHistory(); Vector3 up = targetOrientation * Vector3.up; velocity = velocity.ProjectOntoPlane(up); if (!velocity.AlmostZero()) { mHeadingTracker.Add(velocity); } velocity = mHeadingTracker.GetReliableHeading(); if (!velocity.AlmostZero()) { return(UnityVectorExtensions.SignedAngle(targetOrientation * Vector3.forward, velocity, up)); } // If no reliable heading, then stay where we are. return(currentHeading); }
/// <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 than 0, no damping is done.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { //UnityEngine.Profiling.Profiler.BeginSample("CinemachineOrbitalTransposer.MutateCameraState"); InitPrevFrameStateInfo(ref curState, deltaTime); // Update the heading if (FollowTarget != PreviousTarget) { PreviousTarget = FollowTarget; mTargetRigidBody = (PreviousTarget == null) ? null : PreviousTarget.GetComponent <Rigidbody>(); mLastTargetPosition = (PreviousTarget == null) ? Vector3.zero : PreviousTarget.position; mHeadingTracker = null; } if (!m_HeadingIsSlave) { UpdateHeading(deltaTime, curState.ReferenceUp); } if (IsValid) { mLastTargetPosition = FollowTarget.position; // Track the target, with damping Vector3 pos; Quaternion orient; TrackTarget(deltaTime, curState.ReferenceUp, out pos, out orient); // Place the camera curState.ReferenceUp = orient * Vector3.up; float heading = m_XAxis.Value; if (m_BindingMode == BindingMode.SimpleFollow) { m_XAxis.Value = 0; } else { heading += m_Heading.m_HeadingBias; } Quaternion headingRot = Quaternion.AngleAxis(heading, curState.ReferenceUp); Vector3 offset = EffectiveOffset; if (deltaTime >= 0) { Vector3 bypass = (headingRot * offset) - mHeadingPrevFrame * mOffsetPrevFrame; bypass = orient * bypass; curState.PositionDampingBypass = bypass; } orient = orient * headingRot; curState.RawPosition = pos + orient * offset; mHeadingPrevFrame = (m_BindingMode == BindingMode.SimpleFollow) ? Quaternion.identity : headingRot; mOffsetPrevFrame = offset; } //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 less than 0, no damping is done.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { //UnityEngine.Profiling.Profiler.BeginSample("CinemachineOrbitalTransposer.MutateCameraState"); InitPrevFrameStateInfo(ref curState, deltaTime); // Update the heading if (FollowTarget != PreviousTarget) { PreviousTarget = FollowTarget; mTargetRigidBody = PreviousTarget == null ? null : PreviousTarget.GetComponent <Rigidbody>(); mLastTargetPosition = PreviousTarget == null ? Vector3.zero : PreviousTarget.position; mHeadingTracker = null; } var heading = HeadingUpdater(this, deltaTime, curState.ReferenceUp); if (IsValid) { mLastTargetPosition = FollowTarget.position; // Calculate the heading if (m_BindingMode != BindingMode.SimpleFollowWithWorldUp) { heading += m_Heading.m_HeadingBias; } var headingRot = Quaternion.AngleAxis(heading, curState.ReferenceUp); // Track the target, with damping var offset = EffectiveOffset; Vector3 pos; Quaternion orient; TrackTarget(deltaTime, curState.ReferenceUp, headingRot * offset, out pos, out orient); // Place the camera curState.ReferenceUp = orient * Vector3.up; if (deltaTime >= 0) { var bypass = headingRot * offset - mHeadingPrevFrame * mOffsetPrevFrame; bypass = orient * bypass; curState.PositionDampingBypass = bypass; } orient = orient * headingRot; curState.RawPosition = pos + orient * offset; mHeadingPrevFrame = m_BindingMode == BindingMode.SimpleFollowWithWorldUp ? Quaternion.identity : headingRot; mOffsetPrevFrame = offset; } //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 less than 0, no damping is done.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { InitPrevFrameStateInfo(ref curState, deltaTime); // Update the heading if (FollowTarget != PreviousTarget) { PreviousTarget = FollowTarget; mTargetRigidBody = (PreviousTarget == null) ? null : PreviousTarget.GetComponent <Rigidbody>(); mLastTargetPosition = (PreviousTarget == null) ? Vector3.zero : PreviousTarget.position; mHeadingTracker = null; } LastHeading = HeadingUpdater(this, deltaTime, curState.ReferenceUp); float heading = LastHeading; if (IsValid) { mLastTargetPosition = FollowTargetPosition; // Calculate the heading if (m_BindingMode != BindingMode.SimpleFollowWithWorldUp) { heading += m_Heading.m_Bias; } Quaternion headingRot = Quaternion.AngleAxis(heading, Vector3.up); // Track the target, with damping Vector3 offset = EffectiveOffset; Vector3 pos; Quaternion orient; TrackTarget(deltaTime, curState.ReferenceUp, headingRot * offset, out pos, out orient); // Place the camera curState.ReferenceUp = orient * Vector3.up; if (deltaTime >= 0) { Vector3 bypass = (headingRot * offset) - mHeadingPrevFrame * mOffsetPrevFrame; bypass = orient * bypass; curState.PositionDampingBypass = bypass; } orient = orient * headingRot; curState.RawPosition = pos + orient * offset; mHeadingPrevFrame = (m_BindingMode == BindingMode.SimpleFollowWithWorldUp) ? Quaternion.identity : headingRot; mOffsetPrevFrame = offset; } }
// Make sure this is calld only once per frame private float GetTargetHeading(float currentHeading, Quaternion targetOrientation) { if (m_BindingMode == BindingMode.SimpleFollowWithWorldUp) { return(0); } if (FollowTarget == null) { return(currentHeading); } var headingDef = m_Heading.m_Definition; if (headingDef == Heading.HeadingDefinition.Velocity && mTargetRigidBody == null) { headingDef = Heading.HeadingDefinition.PositionDelta; } Vector3 velocity = Vector3.zero; switch (headingDef) { case Heading.HeadingDefinition.PositionDelta: velocity = FollowTargetPosition - mLastTargetPosition; break; case Heading.HeadingDefinition.Velocity: velocity = mTargetRigidBody.velocity; break; case Heading.HeadingDefinition.TargetForward: velocity = FollowTargetRotation * Vector3.forward; break; default: case Heading.HeadingDefinition.WorldForward: return(0); } // Process the velocity and derive the heading from it. Vector3 up = targetOrientation * Vector3.up; velocity = velocity.ProjectOntoPlane(up); if (headingDef != Heading.HeadingDefinition.TargetForward) { int filterSize = m_Heading.m_VelocityFilterStrength * 5; if (mHeadingTracker == null || mHeadingTracker.FilterSize != filterSize) { mHeadingTracker = new HeadingTracker(filterSize); } mHeadingTracker.DecayHistory(); if (!velocity.AlmostZero()) { mHeadingTracker.Add(velocity); } velocity = mHeadingTracker.GetReliableHeading(); } if (!velocity.AlmostZero()) { return(UnityVectorExtensions.SignedAngle( targetOrientation * Vector3.forward, velocity, up)); } // If no reliable heading, then stay where we are. return(currentHeading); }
Vector3 DoTracking(Vector3 currentPosition, Vector3 up, float deltaTime) { if (VirtualCamera.Follow == null) { return(currentPosition); } if (VirtualCamera.Follow != PreviousTarget) { PreviousTarget = VirtualCamera.Follow; mTargetRigidBody = VirtualCamera.Follow.GetComponent <Rigidbody>(); mLastTargetPosition = VirtualCamera.Follow.position; mHeadingTracker = null; } // Heading if (!m_HeadingIsSlave) { UpdateHeading(deltaTime, up, true); } mLastTargetPosition = VirtualCamera.Follow.position; // Where to put the camera Vector3 localTarget = EffectiveOffset(up); localTarget = Quaternion.AngleAxis(m_XAxis.Value + m_HeadingBias, up) * localTarget; // Adjust for damping, which is done in local coords if (deltaTime > 0) { if (m_DampingStyle == DampingStyle.Polar) { // Get the offset in polar Vector3 localCurrent = currentPosition - VirtualCamera.Follow.position; Vector3 currentOnPlane = localCurrent.ProjectOntoPlane(up); Vector3 currentPerpPlane = localCurrent - currentOnPlane; Vector3 targetOnPlane = localTarget.ProjectOntoPlane(up); Vector3 targetPerpPlane = localTarget - targetOnPlane; Vector3 delta = new Vector3( UnityVectorExtensions.SignedAngle(currentOnPlane, targetOnPlane, up), Vector3.Dot(targetPerpPlane - currentPerpPlane, up), (targetOnPlane.magnitude - currentOnPlane.magnitude)); // Apply damping Vector3 trackingSpeeds = TrackingSpeeds; for (int i = 0; i < 3; ++i) { delta[i] *= deltaTime / Mathf.Max(trackingSpeeds[i], deltaTime); } localTarget = currentOnPlane; localTarget += (localTarget.normalized * delta.z); localTarget += currentPerpPlane + (delta.y * up); localTarget = Quaternion.AngleAxis(delta.x, up) * localTarget; } else { Vector3 worldOffset = currentPosition - (VirtualCamera.Follow.position + localTarget); Quaternion localToWorldTransform = Quaternion.LookRotation( VirtualCamera.Follow.rotation * Vector3.forward, up); Vector3 localOffset = Quaternion.Inverse(localToWorldTransform) * worldOffset; Vector3 trackingSpeeds = TrackingSpeeds; for (int i = 0; i < 3; ++i) { localOffset[i] *= deltaTime / Mathf.Max(trackingSpeeds[i], deltaTime); } return(currentPosition - (localToWorldTransform * localOffset)); } } // Return the adjusted rig position return(VirtualCamera.Follow.position + localTarget); }
private float GetTargetHeading(float currentHeading, Vector3 up, float deltaTime) { if (VirtualCamera.Follow == null) { return(currentHeading); } if (m_RecenterToTargetHeading.m_HeadingDerivationMode == Recentering.HeadingDerivationMode.Velocity && mTargetRigidBody == null) { CinemachineDebugLogger.LogWarn( "Attempted to use HeadingDerivationMode.Velocity to calculate heading for {0}. No RigidBody was present on '{1}'. Defaulting to position delta", GetFullName(VirtualCamera.VirtualCameraGameObject), VirtualCamera.Follow); m_RecenterToTargetHeading.m_HeadingDerivationMode = Recentering.HeadingDerivationMode.PositionDelta; } Vector3 velocity = Vector3.zero; switch (m_RecenterToTargetHeading.m_HeadingDerivationMode) { case Recentering.HeadingDerivationMode.PositionDelta: velocity = VirtualCamera.Follow.position - mLastTargetPosition; break; case Recentering.HeadingDerivationMode.Velocity: velocity = mTargetRigidBody.velocity; break; default: case Recentering.HeadingDerivationMode.EulerYRotation: return(VirtualCamera.Follow.rotation.eulerAngles.y); case Recentering.HeadingDerivationMode.WorldHeading: return(m_RecenterToTargetHeading.m_WorldDefaultHeading); } // Process the velocity and derive the heading from it. int filterSize = m_RecenterToTargetHeading.m_VelocityFilterStrength * 5; if (mHeadingTracker == null || mHeadingTracker.FilterSize != filterSize) { mHeadingTracker = new HeadingTracker(filterSize); } mHeadingTracker.DecayHistory(); velocity = velocity.ProjectOntoPlane(up); if (!velocity.AlmostZero()) { mHeadingTracker.Add(velocity); } velocity = mHeadingTracker.GetReliableHeading(); if (!velocity.AlmostZero()) { Vector3 fwd = (-GetBackVector(up)).ProjectOntoPlane(up); return(UnityVectorExtensions.SignedAngle(fwd, velocity, up)); } // If no reliable heading, then stay where we are. return(currentHeading); }