using UnityEngine; using System; using Rokid.UXR.Utility; using System.Runtime.InteropServices; namespace Rokid.UXR.Native { public enum HeadTrackingStatus { Unknow = 0, UnInit = 1, Detecting = 2,//RESERVED Tracking = 3, Track_Limited = 4,//RESERVED Tracking_Bad = 5,//RESERVED Tracking_Paused = 6, Tracking_Stopped = 7, Tracking_Error = 99 } public partial class NativeInterface { public partial class NativeAPI { private static float[] frustum_left = new float[6]; private static float[] frustum_right = new float[6]; private static float[] position = new float[3]; private static float[] rotation = new float[4]; /// /// Get head tracking status /// /// public static HeadTrackingStatus GetHeadTrackingStatus() { if (Utils.IsAndroidPlatfrom()) return (HeadTrackingStatus)Api.getHeadTrackerState(); return HeadTrackingStatus.Tracking; } /// /// Update screen parameters /// [Obsolete] public static void UpdateScreenParams() { if (Utils.IsAndroidPlatfrom()) Api.UpdateScreenParams(); } /// /// Reset center /// public static void Recenter() { if (Utils.IsAndroidPlatfrom()) Api.Recenter(); } /// /// Get debug informatio /// public static string GetDebugInfo() { if (Utils.IsAndroidPlatfrom()) { return Api.getDebugInfoU(); } return null; } /// /// Get left and right eye projection parameters /// /// float[4] {hFov,vFov,near,far} /// float[4] {hFov,vFov,near,far} /// public static void GetUnityFrustum(ref float[] frustum_left, ref float[] frustum_right) { if (!Utils.IsAndroidPlatfrom()) return; if (frustum_left.Length != 4 || frustum_right.Length != 4) { RKLog.Error("====NativeAnd====:+ GetUnityFrustum 参数数组长度不正确"); return; } if (GetFrustum()) { frustum_left[0] = GetHFov(false); frustum_left[1] = GetVFov(false); frustum_left[2] = NativeAPI.frustum_left[4]; frustum_left[3] = NativeAPI.frustum_left[5]; frustum_right[0] = GetHFov(true); frustum_right[1] = GetVFov(true); frustum_right[2] = NativeAPI.frustum_right[4]; frustum_right[3] = NativeAPI.frustum_right[5]; } } /// /// Get left and right eye fov parameters /// /// public static void GetUnityEyeFrustumHalf(bool isRight, ref float[] fov) { if (!Utils.IsAndroidPlatfrom()) return; if (GetFrustum()) { RKLog.KeyInfo($"====GetUnityEyeFrustumHalf====: left fov {Newtonsoft.Json.JsonConvert.SerializeObject(frustum_left)},right fov {Newtonsoft.Json.JsonConvert.SerializeObject(frustum_right)} "); float[] frustum = isRight ? frustum_right : frustum_left; float left = frustum[0]; float right = frustum[1]; float bottom = frustum[2]; float top = frustum[3]; float near = frustum[4]; float RAD2DEG = 180.0f / 3.14159265358979323846f; fov[0] = RAD2DEG * (float)Math.Atan(Math.Abs(left) / near); fov[1] = RAD2DEG * (float)Math.Atan(Math.Abs(right) / near); fov[2] = RAD2DEG * (float)Math.Atan(Math.Abs(top) / near); fov[3] = RAD2DEG * (float)Math.Atan(Math.Abs(bottom) / near); } } /// /// Get left and right eye projection parameters /// /// float[6] {left,right,bottom,top,near,far} /// {left,right,bottom,top,near,far} /// private static bool GetFrustum() { return Api.getFrustum(frustum_left, frustum_right); } /// /// Get vertical field of view /// /// /// public static float GetVFov(bool isRight) { float[] frustum = isRight ? frustum_right : frustum_left; float near = frustum[4]; float top = frustum[3]; float bottom = frustum[2]; float RAD2DEG = 180.0f / 3.14159265358979323846f; float fov = RAD2DEG * (2.0f * (float)Math.Atan((top - bottom) / (2.0f * near))); return fov; } /// /// Get horizontal field of view /// /// /// public static float GetHFov(bool isRight) { float[] frustum = isRight ? frustum_right : frustum_left; float near = frustum[4]; float left = frustum[0]; float right = frustum[1]; float RAD2DEG = 180.0f / 3.14159265358979323846f; float fov = RAD2DEG * (2.0f * (float)Math.Atan((right - left) / (2.0f * near))); return fov; } /// /// Get camera pose /// /// [Obsolete("Use GetHeadPose instead")] public static Pose GetCameraPose(out long timeStamp) { return GetHeadPose(out timeStamp); } /// /// Get current time head pose /// /// public static Pose GetHeadPose(out long timeStamp) { if (Utils.IsAndroidPlatfrom()) { timeStamp = getHeadPoseRHS(position, rotation); Pose pose = new Pose(new Vector3(position[0], position[1], -position[2]), new Quaternion(-rotation[0], -rotation[1], rotation[2], rotation[3])); return pose; } timeStamp = 0; return Pose.identity; } /// /// Input a timestamp to retrieve the head pose at that specific timestamp only for ges. /// /// (t-1000ms ~ t-10ms) /// public static Pose GetHistoryHeadPose(long timestamp) { Pose pose = Pose.identity; if (Utils.IsAndroidPlatfrom()) { getHistoryHeadPoseRHS(timestamp, position, rotation); pose.position = new Vector3(position[0], position[1], -position[2]); pose.rotation = new Quaternion(-rotation[0], -rotation[1], rotation[2], rotation[3]); } return pose; } /// /// It is current physics camera pose /// /// public static Pose GetCameraPhysicsPose(out long timeStamp) { Pose pose = Pose.identity; if (Utils.IsAndroidPlatfrom()) { timeStamp = getHeadPosePysRHS(position, rotation); pose.position = new Vector3(position[0], position[1], -position[2]); pose.rotation = new Quaternion(-rotation[0], -rotation[1], rotation[2], rotation[3]); return pose; } timeStamp = 0; return pose; } /// /// It is history physics camera pose /// /// /// public static Pose GetHistoryCameraPhysicsPose(long timestamp) { Pose pose = Pose.identity; if (Utils.IsAndroidPlatfrom()) { getHistoryHeadPosePysRHS(timestamp, position, rotation); pose.position = new Vector3(position[0], position[1], -position[2]); pose.rotation = new Quaternion(-rotation[0], -rotation[1], rotation[2], rotation[3]); } return pose; } /// /// Get Head Origin Pose /// /// public static Pose GetHeadPoseOrigin() { Pose pose = Pose.identity; if (Utils.IsAndroidPlatfrom()) { getHeadPoseOriginRHS(0, position, rotation); pose.position = new Vector3(position[0], position[1], -position[2]); pose.rotation = new Quaternion(-rotation[0], -rotation[1], rotation[2], rotation[3]); } return pose; } /// /// Get Head Origin Pose /// /// public static Pose GetHeadPoseOffset() { Pose pose = Pose.identity; if (Utils.IsAndroidPlatfrom()) { getHeadPoseOffsetRHS(position, rotation); pose.position = new Vector3(position[0], position[1], -position[2]); pose.rotation = new Quaternion(-rotation[0], -rotation[1], rotation[2], rotation[3]); } return pose; } /// /// SetTrackingType /// /// public static void SetTrackingType(int type) { if (Utils.IsAndroidPlatfrom()) { RKLog.Info($"====NativeAPI====: SetHeadTrackingType :{type}"); Api.setTrackingType(type); } } /// /// Get ost info /// /// public static string GetOSTInfo() { IntPtr calPtr = Api.getGlassCalFile(); if (calPtr != null) { string cal = Marshal.PtrToStringAuto(calPtr); return cal; } else { return null; } } [DllImport(ApiConstants.UXR_GFX_PLUGIN)] private static extern long getHeadPoseRHS(float[] position, float[] orientation); [DllImport(ApiConstants.UXR_GFX_PLUGIN)] private static extern void getHistoryHeadPoseRHS(long timestamp, float[] position, float[] orientation); [DllImport(ApiConstants.UXR_GFX_PLUGIN)] private static extern long getHeadPosePysRHS(float[] position, float[] orientation); [DllImport(ApiConstants.UXR_GFX_PLUGIN)] private static extern void getHeadPoseOriginRHS(long timestamp, float[] position, float[] orientation); [DllImport(ApiConstants.UXR_GFX_PLUGIN)] private static extern void getHeadPoseOffsetRHS(float[] position, float[] orientation); } } }