/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal { using System; using System.Runtime.InteropServices; using UnityEngine; /// 6-dof Head Tracking's Native API . public class NativeHeadTracking { /// The native interface. private NativeInterface m_NativeInterface; /// Gets the handle of the tracking. /// The tracking handle. public UInt64 TrackingHandle { get { return m_NativeInterface.TrackingHandle; } } /// Handle of the head tracking. private UInt64 m_HeadTrackingHandle = 0; /// Gets the handle of the head tracking. /// The head tracking handle. public UInt64 HeadTrackingHandle { get { return m_HeadTrackingHandle; } } /// Constructor. /// The native interface. public NativeHeadTracking(NativeInterface nativeInterface) { m_NativeInterface = nativeInterface; } /// Creates a new bool. /// True if it succeeds, false if it fails. public bool Start() { if (m_NativeInterface.TrackingHandle == 0) { return false; } var result = NativeApi.NRHeadTrackingCreate(m_NativeInterface.TrackingHandle, ref m_HeadTrackingHandle); NativeErrorListener.Check(result, this, "Create"); return result == NativeResult.Success; } /// Gets head pose. /// [in,out] The pose. /// (Optional) The timestamp. /// (Optional) The predict. /// True if it succeeds, false if it fails. public bool GetHeadPose(ref Pose pose, UInt64 timestamp) { if (m_HeadTrackingHandle == 0) { pose = Pose.identity; return false; } UInt64 headPoseHandle = 0; var acquireTrackingPoseResult = NativeApi.NRHeadTrackingAcquireTrackingPose(m_NativeInterface.TrackingHandle, m_HeadTrackingHandle, timestamp, ref headPoseHandle); if (acquireTrackingPoseResult != NativeResult.Success) { return false; } NativeMat4f headpos_native = new NativeMat4f(Matrix4x4.identity); var getPoseResult = NativeApi.NRTrackingPoseGetPose(m_NativeInterface.TrackingHandle, headPoseHandle, ref headpos_native); if (getPoseResult != NativeResult.Success) { return false; } ConversionUtility.ApiPoseToUnityPose(headpos_native, out pose); NativeApi.NRTrackingPoseDestroy(m_NativeInterface.TrackingHandle, headPoseHandle); return (acquireTrackingPoseResult == NativeResult.Success) && (getPoseResult == NativeResult.Success); } public bool GetHeadPoseRecommend(ref Pose pose) { if (m_HeadTrackingHandle == 0) { pose = Pose.identity; return false; } ulong recommend_time = 0; ulong predict_time = 0; var result = NativeApi.NRTrackingGetHMDTimeNanos(m_NativeInterface.TrackingHandle, ref recommend_time); if (result != NativeResult.Success) { return false; } result = NativeApi.NRHeadTrackingGetRecommendPredictTime(m_NativeInterface.TrackingHandle, m_HeadTrackingHandle, ref predict_time); if (result != NativeResult.Success) { return false; } recommend_time += predict_time; return GetHeadPose(ref pose, recommend_time); } public ulong GetHMDTimeNanos() { ulong timestamp = 0; NativeApi.NRTrackingGetHMDTimeNanos(m_NativeInterface.TrackingHandle, ref timestamp); return timestamp; } public bool GetFramePresentHeadPose(ref Pose pose, ref LostTrackingReason lostReason, ref UInt64 timestamp) { if (m_HeadTrackingHandle == 0 || m_NativeInterface.TrackingHandle == 0) { NRDebugger.Error("[NativeTrack] GetFramePresentHeadPose: trackingHandle is zero"); pose = Pose.identity; timestamp = 0; return false; } UInt64 headPoseHandle = 0; m_NativeInterface.NativeRenderring.GetFramePresentTime(ref timestamp); var acquireTrackingPoseResult = NativeApi.NRHeadTrackingAcquireTrackingPose(m_NativeInterface.TrackingHandle, m_HeadTrackingHandle, timestamp, ref headPoseHandle); if (acquireTrackingPoseResult != NativeResult.Success) { // NRDebugger.Warning("[NativeTrack] GetFramePresentHeadPose: acquireTrackingPoseResult={0}", acquireTrackingPoseResult); lostReason = LostTrackingReason.PRE_INITIALIZING; return true; } var trackReasonRst = NativeApi.NRTrackingPoseGetTrackingReason(m_NativeInterface.TrackingHandle, headPoseHandle, ref lostReason); NativeErrorListener.Check(trackReasonRst, this, "GetFramePresentHeadPose-LostReason"); // NRDebugger.Info("[NativeTrack] GetFramePresentHeadPose: getPoseResult={0}, lost_tracking_reason={1}, result={2}", getPoseResult, lost_tracking_reason, result); NativeMat4f headpos_native = new NativeMat4f(Matrix4x4.identity); var getPoseResult = NativeApi.NRTrackingPoseGetPose(m_NativeInterface.TrackingHandle, headPoseHandle, ref headpos_native); NativeErrorListener.Check(getPoseResult, this, "GetFramePresentHeadPose"); ConversionUtility.ApiPoseToUnityPose(headpos_native, out pose); if (float.IsNaN(pose.position.x) || float.IsNaN(pose.position.y) || float.IsNaN(pose.position.z) || float.IsNaN(pose.rotation.x) || float.IsNaN(pose.rotation.y) || float.IsNaN(pose.rotation.z) || float.IsNaN(pose.rotation.w)) { NRDebugger.Error("[NativeTrack] GetFramePresentHeadPose invalid: lostReason={0}, unityPose=\n{1}\nnativePose=\n{2}", lostReason, pose.ToString("F6"), headpos_native.ToString()); } NativeApi.NRTrackingPoseDestroy(m_NativeInterface.TrackingHandle, headPoseHandle); return true; } public bool GetFramePresentTimeByCount(int count, ref UInt64 timestamp) { return m_NativeInterface.NativeRenderring.GetFramePresentTimeByCount(ref timestamp, count); } /// Destroys this object. public void Destroy() { if (m_HeadTrackingHandle == 0) { return; } var result = NativeApi.NRHeadTrackingDestroy(m_NativeInterface.TrackingHandle, m_HeadTrackingHandle); m_HeadTrackingHandle = 0; NativeErrorListener.Check(result, this, "Destroy"); } private partial struct NativeApi { /// Nr head tracking create. /// Handle of the tracking. /// [in,out] Handle of the out head tracking. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRHeadTrackingCreate(UInt64 tracking_handle, ref UInt64 outHeadTrackingHandle); /// Nr tracking get hmd time nanos. /// Handle of the tracking. /// [in,out] The out hmd time nanos. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRTrackingGetHMDTimeNanos(UInt64 tracking_handle, ref UInt64 out_hmd_time_nanos); /// Nr head tracking get recommend predict time. /// Handle of the tracking. /// Handle of the head tracking. /// [in,out] The out predict time nanos. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRHeadTrackingGetRecommendPredictTime( UInt64 tracking_handle, UInt64 head_tracking_handle, ref UInt64 out_predict_time_nanos); /// Nr head tracking acquire tracking pose. /// Handle of the session. /// Handle of the head tracking. /// The hmd time nanos. /// [in,out] Handle of the out tracking pose. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRHeadTrackingAcquireTrackingPose(UInt64 sessionHandle, UInt64 head_tracking_handle, UInt64 hmd_time_nanos, ref UInt64 out_tracking_pose_handle); /// Nr tracking pose get pose. /// Handle of the tracking. /// Handle of the tracking pose. /// [in,out] The out pose. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRTrackingPoseGetPose(UInt64 tracking_handle, UInt64 tracking_pose_handle, ref NativeMat4f out_pose); /// Nr tracking pose get tracking reason. /// Handle of the tracking. /// Handle of the tracking pose. /// [in,out] The out tracking reason. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRTrackingPoseGetTrackingReason(UInt64 tracking_handle, UInt64 tracking_pose_handle, ref LostTrackingReason out_tracking_reason); /// Nr tracking pose destroy. /// Handle of the tracking. /// Handle of the tracking pose. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRTrackingPoseDestroy(UInt64 tracking_handle, UInt64 tracking_pose_handle); /// Nr head tracking destroy. /// Handle of the tracking. /// Handle of the head tracking. /// A NativeResult. [DllImport(NativeConstants.NRNativeLibrary)] public static extern NativeResult NRHeadTrackingDestroy(UInt64 tracking_handle, UInt64 head_tracking_handle); }; } }