using System.Collections.Generic;
namespace UnityEngine.XR.Templates.MR
{
// Copied from XRI Examples. Commit: c40b958
///
/// Makes this object face a target smoothly and along specific axes
///
public class TurnToFace : MonoBehaviour
{
#pragma warning disable 649
[SerializeField, Tooltip("Target to face towards. If not set, this will default to the main camera")]
Transform m_FaceTarget;
[SerializeField, Tooltip("Speed to turn")]
float m_TurnToFaceSpeed = 5f;
[SerializeField, Tooltip("Local rotation offset")]
Vector3 m_RotationOffset = Vector3.zero;
[SerializeField, Tooltip("If enabled, ignore the x axis when rotating")]
bool m_IgnoreX;
[SerializeField, Tooltip("If enabled, ignore the y axis when rotating")]
bool m_IgnoreY;
[SerializeField, Tooltip("If enabled, ignore the z axis when rotating")]
bool m_IgnoreZ;
#pragma warning restore 649
static readonly HashSet k_EnabledInstances = new HashSet();
void OnEnable()
{
transform.rotation = GetTargetRotation(transform.position);
k_EnabledInstances.Add(this);
}
void OnDisable()
{
k_EnabledInstances.Remove(this);
}
void Update()
{
LookAtTarget();
}
///
/// Causes all turn to face layout components to snap to the correct rotation immediately.
///
public static void SnapAll()
{
foreach (var turnToFace in k_EnabledInstances)
{
var instanceTransform = turnToFace.transform;
instanceTransform.rotation = turnToFace.GetTargetRotation(instanceTransform.position);
}
}
///
/// Get the current easing lerp amount that will be used for rotation.
///
/// The easing value based on current delta time.
public float GetCurrentRotationEase()
{
return 1f - Mathf.Exp(-m_TurnToFaceSpeed * Time.unscaledDeltaTime);
}
///
/// Ease the rotation towards the target rotation
///
public void LookAtTarget()
{
var thisTransform = transform;
var targetRotation = GetTargetRotation(thisTransform.position);
var ease = GetCurrentRotationEase();
thisTransform.rotation = Quaternion.Slerp(thisTransform.rotation, targetRotation, ease);
}
void SetDefaultTargetIfNeeded()
{
// Default to main camera
if (m_FaceTarget == null)
{
var mainCamera = Camera.main;
m_FaceTarget = mainCamera == null ? null : mainCamera.transform;
}
}
///
/// Get the target rotation to use for a given position
///
/// The position to compare to the face target when calculating the look direction.
/// The rotation that faces towards the target from the given position.
public Quaternion GetTargetRotation(Vector3 position)
{
SetDefaultTargetIfNeeded();
if (m_FaceTarget == null)
return Quaternion.identity;
var facePosition = m_FaceTarget.position;
var forward = facePosition - position;
var targetRotation = forward.sqrMagnitude > float.Epsilon ? Quaternion.LookRotation(forward, Vector3.up) : Quaternion.identity;
targetRotation *= Quaternion.Euler(m_RotationOffset);
if (m_IgnoreX || m_IgnoreY || m_IgnoreZ)
{
var targetEuler = targetRotation.eulerAngles;
var currentEuler = transform.rotation.eulerAngles;
targetRotation = Quaternion.Euler
(
m_IgnoreX ? currentEuler.x : targetEuler.x,
m_IgnoreY ? currentEuler.y : targetEuler.y,
m_IgnoreZ ? currentEuler.z : targetEuler.z
);
}
return targetRotation;
}
}
}