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; } } }