using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
namespace Ximmerse.XR.Interactions
{
///
/// 身体前向锚点.
/// 代表XR用户身体前面一定偏移量的坐标锚点。
///
public class FrontBodyAnchor : MonoBehaviour
{
#if UNITY_ANDROID || UNITY_EDITOR
public static FrontBodyAnchor instance
{
get; private set;
}
Camera m_MainCamera;
public Transform mainCameraT
{
get
{
if(!m_MainCamera)
{
m_MainCamera = Camera.main;
}
return m_MainCamera.transform;
}
}
[SerializeField]
[Tooltip("Distance along Z-axis from head to dock position.")]
float m_ZDepth = 4;
///
/// Z-depth : canvas z-distance to head.
///
/// The z depth.
public float Z_Depth
{
get
{
return m_ZDepth;
}
set
{
m_ZDepth = value;
}
}
[SerializeField, Tooltip("Force docking every frame")]
bool m_ForceEveryFrame;
///
/// Gets or sets a value indicating whether this force every frame.
///
/// true if force every frame; otherwise, false.
public bool ForceEveryFrame
{
get
{
return m_ForceEveryFrame;
}
set
{
m_ForceEveryFrame = value;
}
}
[SerializeField, Tooltip("Angular diff error to re-dock canvas, smaller values cause frequent re-docking.")]
float m_AngleDiffError = 35;
///
/// Angular diff error to re-dock canvas, smaller values cause frequent re-docking.
///
/// The diff error.
public float AngleDiffError
{
get
{
return m_AngleDiffError;
}
set
{
m_AngleDiffError = value;
}
}
[SerializeField, Tooltip("Delay time to start docking.")]
float m_DockDelay = 0.5f;
///
/// Gets or sets the dock delay.
///
/// The dock delay.
public float DockDelay
{
get
{
return m_DockDelay;
}
set
{
m_DockDelay = value;
}
}
[SerializeField, Min(0.1f)]
[Tooltip("The smaller damp time is , the faster the transform dock to eye's front.")]
float m_DampTime = 0.3f;
///
/// Gets or sets the damp time. The smaller damp time is , the faster the transform dock to eye's front.
///
/// The damp time.
public float DampTime
{
get
{
return m_DampTime;
}
set
{
m_DampTime = value;
}
}
[SerializeField]
//[Tooltip("The smaller damp time is , the faster the transform dock to eye's front.")]
bool m_FollowWithPitch;
///
/// Gets or sets the damp time. The smaller damp time is , the faster the transform dock to eye's front.
///
/// The damp time.
public bool FollowWithPitch
{
get
{
return m_FollowWithPitch;
}
set
{
m_FollowWithPitch = value;
}
}
///
/// offset of docker position.
/// modify by leaf.2019.08.30
///
public Vector3 PositionOffset;
bool m_Docking = false;
float dampSpeed = 0;
float dockEulerY;
float dockEulerX;
float? m_DockingStartTime;
Transform m_HeadTransform;
Transform headTransform
{
get
{
if (m_HeadTransform == null)
{
m_HeadTransform = Camera.main.transform;
}
return m_HeadTransform;
}
}
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
IEnumerator Start()
{
while (!mainCameraT)
{
yield return null;
}
//calculate dock position and rotation:
Quaternion fwdQ = Quaternion.Euler(0, headTransform.eulerAngles.y, 0);
transform.position = headTransform.position + fwdQ * Vector3.forward * m_ZDepth;
transform.rotation = fwdQ;
m_Docking = false;
dockEulerY = headTransform.eulerAngles.y;
dockEulerX = headTransform.eulerAngles.x;
}
// Update is called once per frame
void LateUpdate()
{
var headT = headTransform;
float headEulerY = headT.eulerAngles.y;
float headEulerX = headT.eulerAngles.x;
float eulerYDiff = Quaternion.Angle(Quaternion.Euler(0, headEulerY, 0), Quaternion.Euler(0, dockEulerY, 0));
float eulerXDiff = Quaternion.Angle(Quaternion.Euler(headEulerX, 0, 0), Quaternion.Euler(dockEulerX, 0, 0));
if (m_ForceEveryFrame || Mathf.Abs(eulerYDiff) >= m_AngleDiffError || (FollowWithPitch && Mathf.Abs(eulerXDiff) >= m_AngleDiffError))
{
m_Docking = true;
if (m_DockingStartTime.HasValue == false)
{
m_DockingStartTime = Time.time + m_DockDelay;
}
}
if (m_Docking)
{
if (m_DockingStartTime.HasValue && Time.time < m_DockingStartTime.Value)
{
//wait for delay time
}
else
{
if (m_DampTime > 0)
{
dockEulerY = Mathf.SmoothDampAngle(dockEulerY, headEulerY, ref dampSpeed, m_DampTime);
float eulerYDiff2 = Quaternion.Angle(Quaternion.Euler(0, headEulerY, 0), Quaternion.Euler(0, dockEulerY, 0));
if (eulerYDiff2 <= 2.5f)
{
m_Docking = false;
m_DockingStartTime = null;//reset docking start time
}
if (FollowWithPitch)
{
dockEulerX = Mathf.SmoothDampAngle(dockEulerX, headEulerX, ref dampSpeed, m_DampTime);
float eulerXDiff2 = Quaternion.Angle(Quaternion.Euler(0, headEulerX, 0), Quaternion.Euler(0, dockEulerX, 0));
if (eulerXDiff2 <= 2.5f)
{
m_Docking = false;
m_DockingStartTime = null;//reset docking start time
}
}
}
else
{
dockEulerY = headEulerY;
if (FollowWithPitch)
{
dockEulerX = headEulerX;
}
}
}
if (FollowWithPitch)
{
transform.rotation = Quaternion.Euler(dockEulerX, dockEulerY, 0);
}
else
{
transform.rotation = Quaternion.Euler(0, dockEulerY, 0);
}
}
//Update pos:
// modify by leaf.2019.08.30
if (FollowWithPitch)
{
transform.position = headTransform.position + Quaternion.Euler(dockEulerX, dockEulerY, 0) * Vector3.forward * m_ZDepth + PositionOffset;
}
else
{
transform.position = headTransform.position + Quaternion.Euler(0, dockEulerY, 0) * Vector3.forward * m_ZDepth + PositionOffset;
}
}
#endif
}
}