427 lines
21 KiB
C#
427 lines
21 KiB
C#
|
|
using System;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace Unity.Cinemachine.TargetTracking
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// The coordinate space to use when interpreting the offset from the target
|
||
|
|
/// </summary>
|
||
|
|
public enum BindingMode
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Camera will be bound to the Follow target using a frame of reference consisting
|
||
|
|
/// of the target's local frame at the moment when the virtual camera was enabled,
|
||
|
|
/// or when the target was assigned.
|
||
|
|
/// </summary>
|
||
|
|
LockToTargetOnAssign = 0,
|
||
|
|
/// <summary>
|
||
|
|
/// Camera will be bound to the Follow target using a frame of reference consisting
|
||
|
|
/// of the target's local frame, with the tilt and roll zeroed out.
|
||
|
|
/// </summary>
|
||
|
|
LockToTargetWithWorldUp = 1,
|
||
|
|
/// <summary>
|
||
|
|
/// Camera will be bound to the Follow target using a frame of reference consisting
|
||
|
|
/// of the target's local frame, with the roll zeroed out.
|
||
|
|
/// </summary>
|
||
|
|
LockToTargetNoRoll = 2,
|
||
|
|
/// <summary>
|
||
|
|
/// Camera will be bound to the Follow target using the target's local frame.
|
||
|
|
/// </summary>
|
||
|
|
LockToTarget = 3,
|
||
|
|
/// <summary>Camera will be bound to the Follow target using a world space offset.</summary>
|
||
|
|
WorldSpace = 4,
|
||
|
|
/// <summary>Offsets will be calculated relative to the target, using Camera-local axes</summary>
|
||
|
|
LazyFollow = 5
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>How to calculate the angular damping for the target orientation</summary>
|
||
|
|
public enum AngularDampingMode
|
||
|
|
{
|
||
|
|
/// <summary>Use Euler angles to specify damping values.
|
||
|
|
/// Subject to gimbal-lock when pitch is steep.</summary>
|
||
|
|
Euler,
|
||
|
|
/// <summary>
|
||
|
|
/// Use quaternions to calculate angular damping.
|
||
|
|
/// No per-channel control, but not susceptible to gimbal-lock</summary>
|
||
|
|
Quaternion
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Settings to control damping for target tracking.
|
||
|
|
/// </summary>
|
||
|
|
[Serializable]
|
||
|
|
public struct TrackerSettings
|
||
|
|
{
|
||
|
|
/// <summary>The coordinate space to use when interpreting the offset from the target</summary>
|
||
|
|
[Tooltip("The coordinate space to use when interpreting the offset from the target. This is also "
|
||
|
|
+ "used to set the camera's Up vector, which will be maintained when aiming the camera.")]
|
||
|
|
public BindingMode BindingMode;
|
||
|
|
|
||
|
|
/// <summary>How aggressively the camera tries to maintain the offset, per axis.
|
||
|
|
/// Small numbers are more responsive, rapidly translating the camera to keep the target's
|
||
|
|
/// offset. Larger numbers give a more heavy slowly responding camera.
|
||
|
|
/// Using different settings per axis can yield a wide range of camera behaviors</summary>
|
||
|
|
[Tooltip("How aggressively the camera tries to maintain the offset, per axis. Small numbers "
|
||
|
|
+ "are more responsive, rapidly translating the camera to keep the target's offset. "
|
||
|
|
+ "Larger numbers give a more heavy slowly responding camera. Using different settings per "
|
||
|
|
+ "axis can yield a wide range of camera behaviors.")]
|
||
|
|
public Vector3 PositionDamping;
|
||
|
|
|
||
|
|
/// <summary>How to calculate the angular damping for the target orientation.
|
||
|
|
/// Use Quaternion if you expect the target to take on very steep pitches, which would
|
||
|
|
/// be subject to gimbal lock if Eulers are used.</summary>
|
||
|
|
public AngularDampingMode AngularDampingMode;
|
||
|
|
|
||
|
|
/// <summary>How aggressively the camera tries to track the target's rotation, per axis.
|
||
|
|
/// Small numbers are more responsive. Larger numbers give a more heavy slowly responding camera.</summary>
|
||
|
|
[Tooltip("How aggressively the camera tries to track the target's rotation, per axis. "
|
||
|
|
+ "Small numbers are more responsive. Larger numbers give a more heavy slowly responding camera.")]
|
||
|
|
public Vector3 RotationDamping;
|
||
|
|
|
||
|
|
/// <summary>How aggressively the camera tries to track the target's rotation.
|
||
|
|
/// Small numbers are more responsive. Larger numbers give a more heavy slowly responding camera.</summary>
|
||
|
|
[Range(0f, 20f)]
|
||
|
|
[Tooltip("How aggressively the camera tries to track the target's rotation. "
|
||
|
|
+ "Small numbers are more responsive. Larger numbers give a more heavy slowly responding camera.")]
|
||
|
|
public float QuaternionDamping;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get the default tracking settings
|
||
|
|
/// </summary>
|
||
|
|
public static TrackerSettings Default => new TrackerSettings
|
||
|
|
{
|
||
|
|
BindingMode = BindingMode.WorldSpace,
|
||
|
|
PositionDamping = Vector3.one,
|
||
|
|
AngularDampingMode = AngularDampingMode.Euler,
|
||
|
|
RotationDamping = Vector3.one,
|
||
|
|
QuaternionDamping = 1
|
||
|
|
};
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Called from OnValidate(). Makes sure the settings are sensible.
|
||
|
|
/// </summary>
|
||
|
|
public void Validate()
|
||
|
|
{
|
||
|
|
PositionDamping.x = Mathf.Max(0, PositionDamping.x);
|
||
|
|
PositionDamping.y = Mathf.Max(0, PositionDamping.y);
|
||
|
|
PositionDamping.z = Mathf.Max(0, PositionDamping.z);
|
||
|
|
RotationDamping.x = Mathf.Max(0, RotationDamping.x);
|
||
|
|
RotationDamping.y = Mathf.Max(0, RotationDamping.y);
|
||
|
|
RotationDamping.z = Mathf.Max(0, RotationDamping.z);
|
||
|
|
QuaternionDamping = Mathf.Max(0, QuaternionDamping);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Helpers for TrackerSettings
|
||
|
|
/// </summary>
|
||
|
|
public static class TrackerSettingsExtensions
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Report maximum damping time needed for the current binding mode.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="s">The tracker settings</param>
|
||
|
|
/// <returns>Highest damping setting in this mode</returns>
|
||
|
|
public static float GetMaxDampTime(this TrackerSettings s)
|
||
|
|
{
|
||
|
|
var d = s.GetEffectivePositionDamping();
|
||
|
|
var d2 = s.AngularDampingMode == AngularDampingMode.Euler
|
||
|
|
? s.GetEffectiveRotationDamping() : new Vector3(s.QuaternionDamping, 0, 0);
|
||
|
|
var a = Mathf.Max(d.x, Mathf.Max(d.y, d.z));
|
||
|
|
var b = Mathf.Max(d2.x, Mathf.Max(d2.y, d2.z));
|
||
|
|
return Mathf.Max(a, b);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get the effective position damping setting for current binding mode.
|
||
|
|
/// For some binding modes, some axes are not damped.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="s">The tracker settings</param>
|
||
|
|
/// <returns>The damping settings applicable for this binding mode</returns>
|
||
|
|
internal static Vector3 GetEffectivePositionDamping(this TrackerSettings s)
|
||
|
|
{
|
||
|
|
return s.BindingMode == BindingMode.LazyFollow
|
||
|
|
? new Vector3(0, s.PositionDamping.y, s.PositionDamping.z) : s.PositionDamping;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get the effective rotation damping setting for current binding mode.
|
||
|
|
/// For some binding modes, some axes are not damped.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="s">The tracker settings</param>
|
||
|
|
/// <returns>The damping settings applicable for this binding mode</returns>
|
||
|
|
internal static Vector3 GetEffectiveRotationDamping(this TrackerSettings s)
|
||
|
|
{
|
||
|
|
switch (s.BindingMode)
|
||
|
|
{
|
||
|
|
case BindingMode.LockToTargetNoRoll:
|
||
|
|
return new Vector3(s.RotationDamping.x, s.RotationDamping.y, 0);
|
||
|
|
case BindingMode.LockToTargetWithWorldUp:
|
||
|
|
return new Vector3(0, s.RotationDamping.y, 0);
|
||
|
|
case BindingMode.WorldSpace:
|
||
|
|
case BindingMode.LazyFollow:
|
||
|
|
return Vector3.zero;
|
||
|
|
default:
|
||
|
|
return s.RotationDamping;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Helper object for implementing target following with damping
|
||
|
|
/// </summary>
|
||
|
|
struct Tracker
|
||
|
|
{
|
||
|
|
/// <summary>State information for damping</summary>
|
||
|
|
public Vector3 PreviousTargetPosition { get; private set; }
|
||
|
|
|
||
|
|
/// <summary>State information for damping</summary>
|
||
|
|
public Quaternion PreviousReferenceOrientation { get; private set; }
|
||
|
|
|
||
|
|
Vector3 m_PreviousOffset;
|
||
|
|
Vector3 m_PreviousTargetPositionDampingOffset;
|
||
|
|
|
||
|
|
Quaternion m_TargetOrientationOnAssign;
|
||
|
|
Transform m_PreviousTarget;
|
||
|
|
|
||
|
|
/// <summary>Initializes the state for previous frame if appropriate.</summary>
|
||
|
|
/// <param name="component">The component caller</param>
|
||
|
|
/// <param name="deltaTime">Current effective deltaTime.</param>
|
||
|
|
/// <param name="bindingMode">Current binding mode for damping and offset</param>
|
||
|
|
/// <param name="targetOffset">Offset from target root, in target-local space</param>
|
||
|
|
/// <param name="up">Current effective world up direction.</param>
|
||
|
|
public void InitStateInfo(
|
||
|
|
CinemachineComponentBase component, float deltaTime,
|
||
|
|
BindingMode bindingMode, Vector3 targetOffset, Vector3 up)
|
||
|
|
{
|
||
|
|
bool prevStateValid = deltaTime >= 0 && component.VirtualCamera.PreviousStateIsValid;
|
||
|
|
if (m_PreviousTarget != component.FollowTarget || !prevStateValid)
|
||
|
|
{
|
||
|
|
m_PreviousTarget = component.FollowTarget;
|
||
|
|
m_TargetOrientationOnAssign = component.FollowTargetRotation;
|
||
|
|
}
|
||
|
|
if (!prevStateValid)
|
||
|
|
{
|
||
|
|
PreviousTargetPosition = component.FollowTargetPosition;
|
||
|
|
var state = component.VcamState;
|
||
|
|
PreviousReferenceOrientation = GetReferenceOrientation(component, bindingMode, targetOffset, up, ref state);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Internal API for the Inspector Editor, so it can draw a marker at the target</summary>
|
||
|
|
/// <param name="component">The component caller</param>
|
||
|
|
/// <param name="bindingMode">Current binding mode for damping and offset</param>
|
||
|
|
/// <param name="targetOffset">Offset from target root, in target-local space</param>
|
||
|
|
/// <param name="worldUp">Current effective world up</param>
|
||
|
|
/// <param name="cameraState">Calling camera's state - will not be modified</param>
|
||
|
|
/// <returns>The rotation of the Follow target, as understood by the Transposer.
|
||
|
|
/// This is not necessarily the same thing as the actual target rotation</returns>
|
||
|
|
public readonly Quaternion GetReferenceOrientation(
|
||
|
|
CinemachineComponentBase component,
|
||
|
|
BindingMode bindingMode, Vector3 targetOffset,
|
||
|
|
Vector3 worldUp, ref CameraState cameraState)
|
||
|
|
{
|
||
|
|
if (bindingMode == BindingMode.WorldSpace)
|
||
|
|
return Quaternion.identity;
|
||
|
|
if (component.FollowTarget != null)
|
||
|
|
{
|
||
|
|
var targetOrientation = component.FollowTargetRotation;
|
||
|
|
switch (bindingMode)
|
||
|
|
{
|
||
|
|
case BindingMode.LockToTargetOnAssign:
|
||
|
|
return m_TargetOrientationOnAssign;
|
||
|
|
case BindingMode.LockToTargetWithWorldUp:
|
||
|
|
{
|
||
|
|
Vector3 fwd = (targetOrientation * Vector3.forward).ProjectOntoPlane(worldUp);
|
||
|
|
if (fwd.AlmostZero())
|
||
|
|
break;
|
||
|
|
return Quaternion.LookRotation(fwd, worldUp);
|
||
|
|
}
|
||
|
|
case BindingMode.LockToTargetNoRoll:
|
||
|
|
return Quaternion.LookRotation(targetOrientation * Vector3.forward, worldUp);
|
||
|
|
case BindingMode.LockToTarget:
|
||
|
|
return targetOrientation;
|
||
|
|
case BindingMode.LazyFollow:
|
||
|
|
{
|
||
|
|
var pos = component.FollowTargetPosition + component.FollowTargetRotation * targetOffset;
|
||
|
|
var fwd = (pos - cameraState.RawPosition).ProjectOntoPlane(worldUp);
|
||
|
|
if (fwd.AlmostZero())
|
||
|
|
break;
|
||
|
|
return Quaternion.LookRotation(fwd, worldUp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Gimbal lock situation - use previous orientation if it exists
|
||
|
|
if (PreviousReferenceOrientation == new Quaternion(0, 0, 0, 0))
|
||
|
|
return Quaternion.identity;
|
||
|
|
return PreviousReferenceOrientation.normalized;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Positions the virtual camera according to the transposer rules.</summary>
|
||
|
|
/// <param name="component">The component caller</param>
|
||
|
|
/// <param name="deltaTime">Used for damping. If less than 0, no damping is done.</param>
|
||
|
|
/// <param name="up">Current camera up</param>
|
||
|
|
/// <param name="desiredCameraOffset">Where we want to put the camera relative to the follow target</param>
|
||
|
|
/// <param name="settings">Tracker settings</param>
|
||
|
|
/// <param name="targetOffset">Offset from target root, in target-local space</param>
|
||
|
|
/// <param name="cameraState">Calling camera's state</param>
|
||
|
|
/// <param name="outTargetPosition">Resulting camera position</param>
|
||
|
|
/// <param name="outTargetOrient">Damped target orientation</param>
|
||
|
|
public void TrackTarget(
|
||
|
|
CinemachineComponentBase component,
|
||
|
|
float deltaTime, Vector3 up, Vector3 desiredCameraOffset,
|
||
|
|
in TrackerSettings settings, Vector3 targetOffset, ref CameraState cameraState,
|
||
|
|
out Vector3 outTargetPosition, out Quaternion outTargetOrient)
|
||
|
|
{
|
||
|
|
var vcam = component.VirtualCamera;
|
||
|
|
|
||
|
|
// Get the damped reference rotation
|
||
|
|
var referenceRot = GetReferenceOrientation(component, settings.BindingMode, targetOffset, up, ref cameraState);
|
||
|
|
var dampedRot = referenceRot;
|
||
|
|
bool prevStateValid = deltaTime >= 0 && vcam.PreviousStateIsValid;
|
||
|
|
if (prevStateValid && settings.BindingMode != BindingMode.LazyFollow && settings.BindingMode != BindingMode.WorldSpace)
|
||
|
|
{
|
||
|
|
if (settings.AngularDampingMode == AngularDampingMode.Quaternion
|
||
|
|
&& settings.BindingMode == BindingMode.LockToTarget)
|
||
|
|
{
|
||
|
|
float t = vcam.DetachedFollowTargetDamp(1, settings.QuaternionDamping, deltaTime);
|
||
|
|
dampedRot = Quaternion.Slerp(PreviousReferenceOrientation, referenceRot, t);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var relative = (Quaternion.Inverse(PreviousReferenceOrientation) * referenceRot).eulerAngles;
|
||
|
|
for (int i = 0; i < 3; ++i)
|
||
|
|
{
|
||
|
|
if (relative[i] > 180)
|
||
|
|
relative[i] -= 360;
|
||
|
|
if (Mathf.Abs(relative[i]) < 0.01f) // correct for precision drift
|
||
|
|
relative[i] = 0;
|
||
|
|
}
|
||
|
|
relative = vcam.DetachedFollowTargetDamp(relative, settings.GetEffectiveRotationDamping(), deltaTime);
|
||
|
|
dampedRot = PreviousReferenceOrientation * Quaternion.Euler(relative);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
PreviousReferenceOrientation = dampedRot;
|
||
|
|
|
||
|
|
// Get the target position with the target offset applied
|
||
|
|
var targetPosition = GetTargetPositionWithOffset(component, settings.BindingMode, targetOffset, dampedRot);
|
||
|
|
|
||
|
|
var currentPosition = PreviousTargetPosition;
|
||
|
|
var previousOffset = prevStateValid ? m_PreviousOffset : desiredCameraOffset;
|
||
|
|
var offsetDelta = desiredCameraOffset - previousOffset;
|
||
|
|
if (offsetDelta.sqrMagnitude > 0.01f)
|
||
|
|
{
|
||
|
|
var q = UnityVectorExtensions.SafeFromToRotation(m_PreviousOffset, desiredCameraOffset, up);
|
||
|
|
currentPosition = targetPosition + q * (PreviousTargetPosition - targetPosition);
|
||
|
|
}
|
||
|
|
m_PreviousOffset = desiredCameraOffset;
|
||
|
|
|
||
|
|
// Adjust for damping, which is done in camera-offset-local coords
|
||
|
|
var positionDelta = targetPosition - currentPosition;
|
||
|
|
if (prevStateValid)
|
||
|
|
{
|
||
|
|
var dampingSpace = desiredCameraOffset.AlmostZero()
|
||
|
|
? vcam.State.RawOrientation : Quaternion.LookRotation(dampedRot * desiredCameraOffset, up);
|
||
|
|
var localDelta = Quaternion.Inverse(dampingSpace) * positionDelta;
|
||
|
|
localDelta = component.VirtualCamera.DetachedFollowTargetDamp(
|
||
|
|
localDelta, settings.GetEffectivePositionDamping(), deltaTime);
|
||
|
|
positionDelta = dampingSpace * localDelta;
|
||
|
|
}
|
||
|
|
currentPosition += positionDelta;
|
||
|
|
|
||
|
|
outTargetPosition = PreviousTargetPosition = currentPosition;
|
||
|
|
outTargetOrient = dampedRot;
|
||
|
|
m_PreviousTargetPositionDampingOffset = currentPosition - targetPosition;
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector3 GetTargetPositionWithOffset(
|
||
|
|
CinemachineComponentBase component, BindingMode bindingMode, Vector3 targetOffset, Quaternion referenceOrient)
|
||
|
|
{
|
||
|
|
return component.FollowTargetPosition
|
||
|
|
+ (bindingMode == BindingMode.LazyFollow ? component.FollowTargetRotation : referenceOrient) * targetOffset;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Return a new damped target position that respects the minimum
|
||
|
|
/// distance from the real target</summary>
|
||
|
|
/// <param name="component">The component caller</param>
|
||
|
|
/// <param name="dampedTargetPos">The effective position of the target, after damping</param>
|
||
|
|
/// <param name="cameraOffset">Desired camera offset from target</param>
|
||
|
|
/// <param name="cameraFwd">Current camera local +Z direction</param>
|
||
|
|
/// <param name="up">Effective world up</param>
|
||
|
|
/// <param name="actualTargetPos">The real undamped target position</param>
|
||
|
|
/// <returns>New camera offset, potentially adjusted to respect minimum distance from target</returns>
|
||
|
|
public Vector3 GetOffsetForMinimumTargetDistance(
|
||
|
|
CinemachineComponentBase component,
|
||
|
|
Vector3 dampedTargetPos, Vector3 cameraOffset,
|
||
|
|
Vector3 cameraFwd, Vector3 up, Vector3 actualTargetPos)
|
||
|
|
{
|
||
|
|
var posOffset = Vector3.zero;
|
||
|
|
if (component.VirtualCamera.FollowTargetAttachment > 1 - UnityVectorExtensions.Epsilon)
|
||
|
|
{
|
||
|
|
cameraOffset = cameraOffset.ProjectOntoPlane(up);
|
||
|
|
var minDistance = cameraOffset.magnitude * 0.2f;
|
||
|
|
if (minDistance > 0)
|
||
|
|
{
|
||
|
|
actualTargetPos = actualTargetPos.ProjectOntoPlane(up);
|
||
|
|
dampedTargetPos = dampedTargetPos.ProjectOntoPlane(up);
|
||
|
|
var cameraPos = dampedTargetPos + cameraOffset;
|
||
|
|
var d = Vector3.Dot(
|
||
|
|
actualTargetPos - cameraPos,
|
||
|
|
(dampedTargetPos - cameraPos).normalized);
|
||
|
|
if (d < minDistance)
|
||
|
|
{
|
||
|
|
var dir = actualTargetPos - dampedTargetPos;
|
||
|
|
var len = dir.magnitude;
|
||
|
|
if (len < 0.01f)
|
||
|
|
dir = -cameraFwd.ProjectOntoPlane(up);
|
||
|
|
else
|
||
|
|
dir /= len;
|
||
|
|
posOffset = dir * (minDistance - d);
|
||
|
|
}
|
||
|
|
PreviousTargetPosition += posOffset;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return posOffset;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>This is called to notify the user that a target got warped,
|
||
|
|
/// so that we can update its internal state to make the camera
|
||
|
|
/// also warp seamlessly.</summary>
|
||
|
|
/// <param name="positionDelta">The amount the target's position changed</param>
|
||
|
|
public void OnTargetObjectWarped(Vector3 positionDelta)
|
||
|
|
{
|
||
|
|
PreviousTargetPosition += positionDelta;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Force the virtual camera to assume a given position and orientation
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="component">The component caller</param>
|
||
|
|
/// <param name="bindingMode">Current binding mode for damping and offset</param>
|
||
|
|
/// <param name="targetOffset">Offset from target root, in target-local space</param>
|
||
|
|
/// <param name="newState">Calling camera's new state</param>
|
||
|
|
public void OnForceCameraPosition(
|
||
|
|
CinemachineComponentBase component,
|
||
|
|
BindingMode bindingMode, Vector3 targetOffset,
|
||
|
|
ref CameraState newState)
|
||
|
|
{
|
||
|
|
var state = component.VcamState; // old state
|
||
|
|
var prevOrient = GetReferenceOrientation(
|
||
|
|
component, bindingMode, targetOffset, newState.ReferenceUp, ref state);
|
||
|
|
var targetPos = GetTargetPositionWithOffset(component, bindingMode, targetOffset, prevOrient);
|
||
|
|
|
||
|
|
var orient = GetReferenceOrientation(
|
||
|
|
component, bindingMode, targetOffset, newState.ReferenceUp, ref newState);
|
||
|
|
m_PreviousOffset = orient * (Quaternion.Inverse(prevOrient) * m_PreviousOffset);
|
||
|
|
PreviousReferenceOrientation = orient;
|
||
|
|
|
||
|
|
// Rotate the damping data also, to preserve position damping integrity
|
||
|
|
var deltaRot = newState.GetFinalOrientation() * Quaternion.Inverse(state.GetFinalOrientation());
|
||
|
|
m_PreviousTargetPositionDampingOffset = deltaRot * m_PreviousTargetPositionDampingOffset;
|
||
|
|
PreviousTargetPosition = targetPos + m_PreviousTargetPositionDampingOffset;
|
||
|
|
if (bindingMode == BindingMode.WorldSpace)
|
||
|
|
m_PreviousOffset = deltaRot * m_PreviousOffset;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|