using System;
using System.Collections.Generic;
using Rokid.UXR.Native;
using Rokid.UXR.Utility;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Rokid.UXR.Interaction
{
///
/// Base Ray Pose
///
public abstract class BaseRayPose : MonoBehaviour
{
[Serializable]
public class EditorParams
{
[Tooltip("是否使用鼠标模拟射线Rotate")]
public bool useMouseRotate = true;
[Tooltip("射线是否跟随相机,只在编辑器生效")]
public bool followCameraInEditor = true;
[Tooltip("相机空间下的局部坐标,只有在followCamera为真的情况下生效")]
public Vector3 localPositionInCameraSpace = new Vector3(0, -0.1f, 0);
public float maxDistanceInEditor = 10.0f;
[HideInInspector]
public float raycastDistance = -1.0f;
public BaseRayCaster rayCaster;
public static readonly RaycastHit[] hits = new RaycastHit[4];
public readonly List sortedRaycastResults = new List();
public Transform rayOrigin;
}
[SerializeField, Tooltip("编辑器模拟参数")]
private EditorParams editorParams;
private Transform hostTransform;
protected virtual void Start()
{
if (editorParams.rayCaster == null)
editorParams.rayCaster = GetComponent();
hostTransform = editorParams.rayOrigin == null ? transform : editorParams.rayOrigin;
}
protected virtual void Update()
{
#if UNITY_EDITOR
if (editorParams.useMouseRotate)
{
UpdateInEditor();
}
#endif
}
#if UNITY_EDITOR
protected virtual void UpdateInEditor()
{
if (editorParams.followCameraInEditor)
{
hostTransform.position = MainCameraCache.mainCamera.transform.TransformPoint(editorParams.localPositionInCameraSpace);
}
if (editorParams.rayCaster != null)
{
Ray ray = MainCameraCache.mainCamera.ScreenPointToRay(Input.mousePosition);
editorParams.rayCaster.Raycast(ray, Mathf.Infinity, editorParams.sortedRaycastResults);
RaycastResult raycastResult = editorParams.rayCaster.FirstRaycastResult(editorParams.sortedRaycastResults);
if (raycastResult.gameObject != null)
{
Vector3 targetPos = raycastResult.worldPosition;
Vector3 toDirection = targetPos - hostTransform.position;
hostTransform.localRotation = Quaternion.FromToRotation(Vector3.forward, toDirection);
editorParams.raycastDistance = Mathf.Min(editorParams.maxDistanceInEditor, raycastResult.distance);
}
else if (editorParams.raycastDistance > 0.0f)
{
Vector3 targetPos = ray.origin + Mathf.Min(editorParams.maxDistanceInEditor, editorParams.raycastDistance) * ray.direction;
Vector3 toDirection = targetPos - hostTransform.position;
hostTransform.localRotation = Quaternion.FromToRotation(Vector3.forward, toDirection);
}
else
{
hostTransform.localRotation = Quaternion.identity;
}
}
}
#endif
#region LimitInViewField
protected Camera renderCamera;
public Vector4 cursorSize;
private Vector4 _halfFovTan = Vector4.zero;
private Vector4 halfFovTan
{
get
{
if (_halfFovTan != Vector4.zero)
{
return _halfFovTan;
}
#if UNITY_EDITOR
_halfFovTan.x = _halfFovTan.y = _halfFovTan.z = _halfFovTan.w = Mathf.Tan(renderCamera.fieldOfView / 2 * Mathf.Deg2Rad);
return _halfFovTan;
#endif
float[] fov = new float[4];
NativeInterface.NativeAPI.GetUnityEyeFrustumHalf(false, ref fov);
if (fov[0] > 0 && fov[1] > 0 && fov[2] > 0 && fov[3] > 0)
{
_halfFovTan.x = Mathf.Tan(fov[0] * Mathf.Deg2Rad); // Left
_halfFovTan.y = Mathf.Tan(fov[1] * Mathf.Deg2Rad); // Right
_halfFovTan.z = Mathf.Tan(fov[2] * Mathf.Deg2Rad); // Top
_halfFovTan.w = Mathf.Tan(fov[3] * Mathf.Deg2Rad); // Bottom
return _halfFovTan;
}
return Vector4.zero;
}
}
Vector4 GetCameraCorner(float dis)
{
Vector4 corner = Vector4.zero;
corner.z = dis * halfFovTan.z; // Top
corner.w = dis * halfFovTan.w; // Bottom
#if UNITY_EDITOR
corner.x = corner.y = corner.z * renderCamera.aspect;
#else
corner.x = dis * halfFovTan.x; // Left
corner.y = dis * halfFovTan.y; // Right
#endif
return corner;
}
protected void LimitInViewField()
{
transform.position = renderCamera.transform.position;
Vector3 pointPosition = transform.forward + transform.position;
Vector3 pointInCamera = renderCamera.transform.InverseTransformPoint(pointPosition);
//点在相机forward上的距离
float dis = pointInCamera.z;
if (dis < 0)
{
dis = -dis;
pointInCamera.z = dis;
}
Vector4 corner = GetCameraCorner(dis);
if (pointInCamera.x < -corner.x + cursorSize.x) // LEFT
{
pointInCamera.x = -corner.x + cursorSize.x;
}
else if (pointInCamera.x > corner.y - cursorSize.w) // Right
{
pointInCamera.x = corner.y - cursorSize.w;
}
if (pointInCamera.y > corner.z - cursorSize.y) // Top
{
pointInCamera.y = corner.z - cursorSize.y;
}
else if (pointInCamera.y < -corner.w + cursorSize.z) // Bottom
{
pointInCamera.y = -corner.w + cursorSize.z;
}
pointPosition = renderCamera.transform.TransformPoint(pointInCamera);
transform.forward = pointPosition - transform.position;
}
#endregion
}
}