/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal
{
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
///
/// Hand Tracking's Native API.
///
internal partial class NativeHandTracking
{
public enum NRHandType
{
NR_HAND_TYPE_UNKNOWN = -1,
NR_HAND_TYPE_LEFT = 0,
NR_HAND_TYPE_RIGHT = 1
}
public enum NRHandJointType
{
NR_HAND_JOINT_TYPE_INVALID = -1,
NR_HAND_JOINT_TYPE_THUMB_0 = 0,
NR_HAND_JOINT_TYPE_THUMB_1 = 1,
NR_HAND_JOINT_TYPE_THUMB_2 = 2,
NR_HAND_JOINT_TYPE_THUMB_3 = 3,
NR_HAND_JOINT_TYPE_INDEX_1 = 4,
NR_HAND_JOINT_TYPE_INDEX_2 = 5,
NR_HAND_JOINT_TYPE_INDEX_3 = 6,
NR_HAND_JOINT_TYPE_INDEX_4 = 7,
NR_HAND_JOINT_TYPE_MIDDLE_1 = 8,
NR_HAND_JOINT_TYPE_MIDDLE_2 = 9,
NR_HAND_JOINT_TYPE_MIDDLE_3 = 10,
NR_HAND_JOINT_TYPE_MIDDLE_4 = 11,
NR_HAND_JOINT_TYPE_RING_1 = 12,
NR_HAND_JOINT_TYPE_RING_2 = 13,
NR_HAND_JOINT_TYPE_RING_3 = 14,
NR_HAND_JOINT_TYPE_RING_4 = 15,
NR_HAND_JOINT_TYPE_PINKY_0 = 16,
NR_HAND_JOINT_TYPE_PINKY_1 = 17,
NR_HAND_JOINT_TYPE_PINKY_2 = 18,
NR_HAND_JOINT_TYPE_PINKY_3 = 19,
NR_HAND_JOINT_TYPE_PINKY_4 = 20,
NR_HAND_JOINT_TYPE_PALM_CENTER = 21,
NR_HAND_JOINT_TYPE_WRIST_BEGIN = 22,
NR_HAND_JOINT_TYPE_WRIST_END = 23,
NR_HAND_JOINT_TYPE_WRIST_CENTER = 24
}
public enum NRHandJointMask : UInt64
{
NR_HAND_JOINT_TYPE_MASK_THUMB_0 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_0),
NR_HAND_JOINT_TYPE_MASK_THUMB_1 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_1),
NR_HAND_JOINT_TYPE_MASK_THUMB_2 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_2),
NR_HAND_JOINT_TYPE_MASK_THUMB_3 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_3),
NR_HAND_JOINT_TYPE_MASK_INDEX_1 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_1),
NR_HAND_JOINT_TYPE_MASK_INDEX_2 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_2),
NR_HAND_JOINT_TYPE_MASK_INDEX_3 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_3),
NR_HAND_JOINT_TYPE_MASK_INDEX_4 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_4),
NR_HAND_JOINT_TYPE_MASK_MIDDLE_1 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_1),
NR_HAND_JOINT_TYPE_MASK_MIDDLE_2 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_2),
NR_HAND_JOINT_TYPE_MASK_MIDDLE_3 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_3),
NR_HAND_JOINT_TYPE_MASK_MIDDLE_4 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_4),
NR_HAND_JOINT_TYPE_MASK_RING_1 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_RING_1),
NR_HAND_JOINT_TYPE_MASK_RING_2 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_RING_2),
NR_HAND_JOINT_TYPE_MASK_RING_3 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_RING_3),
NR_HAND_JOINT_TYPE_MASK_RING_4 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_RING_4),
NR_HAND_JOINT_TYPE_MASK_PINKY_0 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_0),
NR_HAND_JOINT_TYPE_MASK_PINKY_1 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_1),
NR_HAND_JOINT_TYPE_MASK_PINKY_2 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_2),
NR_HAND_JOINT_TYPE_MASK_PINKY_3 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_3),
NR_HAND_JOINT_TYPE_MASK_PINKY_4 = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_4),
NR_HAND_JOINT_TYPE_MASK_PALM_CENTER = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_PALM_CENTER),
NR_HAND_JOINT_TYPE_MASK_WRIST_BEGIN = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_WRIST_BEGIN),
NR_HAND_JOINT_TYPE_MASK_WRIST_END = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_WRIST_END),
NR_HAND_JOINT_TYPE_MASK_WRIST_CENTER = (1L << NRHandJointType.NR_HAND_JOINT_TYPE_WRIST_CENTER),
NR_HAND_JOINT_TYPE_MASK_ALL = 0x7FFFFFFFFFFFFFFF
}
public enum NRGestureType
{
NR_GESTURE_TYPE_UNKNOWN = -1,
NR_GESTURE_TYPE_OPEN_HAND = 0,
NR_GESTURE_TYPE_GRAB = 1,
NR_GESTURE_TYPE_PINCH = 2,
NR_GESTURE_TYPE_POINT = 3,
NR_GESTURE_TYPE_VICTORY = 4,
NR_GESTURE_TYPE_CALL = 5,
NR_GESTURE_TYPE_SYSTEM = 6,
}
public enum NRGestureTypeMask : UInt64
{
NR_GESTURE_TYPE_MASK_OPEN_HAND = (1L << NRGestureType.NR_GESTURE_TYPE_OPEN_HAND),
NR_GESTURE_TYPE_MASK_GRAB = (1L << NRGestureType.NR_GESTURE_TYPE_GRAB),
NR_GESTURE_TYPE_MASK_PINCH = (1L << NRGestureType.NR_GESTURE_TYPE_PINCH),
NR_GESTURE_TYPE_MASK_POINT = (1L << NRGestureType.NR_GESTURE_TYPE_POINT),
NR_GESTURE_TYPE_MASK_VICTORY = (1L << NRGestureType.NR_GESTURE_TYPE_VICTORY),
NR_GESTURE_TYPE_MASK_CALL = (1L << NRGestureType.NR_GESTURE_TYPE_CALL),
NR_GESTURE_TYPE_MASK_SYSTEM = (1L << NRGestureType.NR_GESTURE_TYPE_SYSTEM),
NR_GESTURE_TYPE_MASK_ALL = 0x7FFFFFFFFFFFFFFF
}
public enum NRHandTrackingSupportFunction
{
NR_HANDTRACKING_SUPPORT_TIMESTAMP = 0,
NR_HANDTRACKING_SUPPORT_HAND_JOINT_POSITION = 1,
NR_HANDTRACKING_SUPPORT_HAND_JOINT_ROTATION = 2
}
public enum NRHandTrackingSupportFunctionMask : UInt64
{
NR_HANDTRACKING_SUPPORT_MASK_TIMESTAMP = (1L << NRHandTrackingSupportFunction.NR_HANDTRACKING_SUPPORT_TIMESTAMP),
NR_HANDTRACKING_SUPPORT_MASK_HAND_JOINT_POSITION = (1L << NRHandTrackingSupportFunction.NR_HANDTRACKING_SUPPORT_HAND_JOINT_POSITION),
NR_HANDTRACKING_SUPPORT_MASK_HAND_JOINT_ROTATION = (1L << NRHandTrackingSupportFunction.NR_HANDTRACKING_SUPPORT_HAND_JOINT_ROTATION)
}
private UInt64 m_HandTrackingHandle = 0;
private UInt64 m_TrackingDataHandle = 0;
private UInt64 m_CurrentHMDTimeNanos = 0;
private UInt64 m_AvailableHandJointTypeMask = 0;
private UInt64 m_AvailableGestureTypeMask = 0;
private UInt64 m_SupportedFunctionMask = 0;
private Dictionary m_JointMapping = new Dictionary
{
{NRHandJointType.NR_HAND_JOINT_TYPE_WRIST_CENTER, HandJointID.Wrist},
{NRHandJointType.NR_HAND_JOINT_TYPE_PALM_CENTER, HandJointID.Palm},
{NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_0, HandJointID.ThumbMetacarpal},
{NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_1, HandJointID.ThumbProximal},
{NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_2, HandJointID.ThumbDistal},
{NRHandJointType.NR_HAND_JOINT_TYPE_THUMB_3, HandJointID.ThumbTip},
{NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_1, HandJointID.IndexProximal},
{NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_2, HandJointID.IndexMiddle},
{NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_3, HandJointID.IndexDistal},
{NRHandJointType.NR_HAND_JOINT_TYPE_INDEX_4, HandJointID.IndexTip},
{NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_1, HandJointID.MiddleProximal},
{NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_2, HandJointID.MiddleMiddle},
{NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_3, HandJointID.MiddleDistal},
{NRHandJointType.NR_HAND_JOINT_TYPE_MIDDLE_4, HandJointID.MiddleTip},
{NRHandJointType.NR_HAND_JOINT_TYPE_RING_1, HandJointID.RingProximal},
{NRHandJointType.NR_HAND_JOINT_TYPE_RING_2, HandJointID.RingMiddle},
{NRHandJointType.NR_HAND_JOINT_TYPE_RING_3, HandJointID.RingDistal},
{NRHandJointType.NR_HAND_JOINT_TYPE_RING_4, HandJointID.RingTip},
{NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_0, HandJointID.PinkyMetacarpal},
{NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_1, HandJointID.PinkyProximal},
{NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_2, HandJointID.PinkyMiddle},
{NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_3, HandJointID.PinkyDistal},
{NRHandJointType.NR_HAND_JOINT_TYPE_PINKY_4, HandJointID.PinkyTip}
};
private Transform m_CachedCameraRigTransform; //instead of using this, should use CameraRigTransform
private Transform CameraRigTransform
{
get
{
if (m_CachedCameraRigTransform == null)
{
if (NRSessionManager.Instance != null)
{
m_CachedCameraRigTransform = NRSessionManager.Instance.NRSessionBehaviour.transform;
}
}
return m_CachedCameraRigTransform;
}
}
public NativeHandTracking()
{
var result = NativeApi.NRHandTrackingCreate(ref m_HandTrackingHandle);
NativeErrorListener.Check(result, this, "Create");
}
public bool Start()
{
if (m_HandTrackingHandle == 0)
return false;
var result = NativeApi.NRHandTrackingStart(m_HandTrackingHandle);
NativeErrorListener.Check(result, this, "Start", true);
NativeApi.NRHandTrackingGetAvailableHandJoint(m_HandTrackingHandle, ref m_AvailableHandJointTypeMask);
NativeApi.NRHandTrackingGetAvailableGestureType(m_HandTrackingHandle, ref m_AvailableGestureTypeMask);
NativeApi.NRHandTrackingGetSupportedFunctions(m_HandTrackingHandle, ref m_SupportedFunctionMask);
return result == NativeResult.Success;
}
public void Update(HandState[] handStates)
{
if (m_HandTrackingHandle == 0)
return;
ulong timeStamp = NRFrame.CurrentPoseTimeStamp;
if (timeStamp == 0)
{
NRSessionManager.Instance.NativeAPI.NativeRenderring.GetFramePresentTime(ref timeStamp);
}
if (!TryAcquireHandTrackingDataHandle(timeStamp))
return;
UInt64 hmd_time_nanos = 0;
var timeResult = NativeApi.NRHandTrackingDataGetHMDTimeNanos(m_TrackingDataHandle, ref hmd_time_nanos);
if (timeResult != NativeResult.Success)
{
NativeErrorListener.Check(timeResult, this, "hmd_time_nanos");
}
UInt32 hand_count = 0;
var countResult = NativeApi.NRHandTrackingDataGetHandsCount(m_TrackingDataHandle, ref hand_count);
if (countResult != NativeResult.Success)
{
NativeErrorListener.Check(countResult, this, "hand_count");
}
for (int i = 0; i < handStates.Length; i++)
{
handStates[i].isTracked = false;
handStates[i].pointerPoseValid = false;
handStates[i].currentGesture = HandGesture.None;
}
bool rightHandUpdated = false;
bool leftHandUpdated = false;
for (int i = 0; i < hand_count; i++)
{
UInt64 hand_state_handle = 0;
var handStateCreateResult = NativeApi.NRHandStateCreate(m_TrackingDataHandle, (UInt32)i, ref hand_state_handle);
if (handStateCreateResult != NativeResult.Success)
{
NativeErrorListener.Check(handStateCreateResult, this, "hand_state_handle");
continue;
}
bool isTracked = false;
NativeApi.NRHandStateIsTracked(hand_state_handle, ref isTracked);
NRHandType handType = NRHandType.NR_HAND_TYPE_UNKNOWN;
NativeApi.NRHandStateGetHandType(hand_state_handle, ref handType);
if (!isTracked)
continue;
if (rightHandUpdated && leftHandUpdated)
continue;
HandState handState = null;
if (handType == NRHandType.NR_HAND_TYPE_RIGHT && !rightHandUpdated)
{
handState = handStates[0];
rightHandUpdated = true;
}
else if(handType == NRHandType.NR_HAND_TYPE_LEFT && !leftHandUpdated)
{
handState = handStates[1];
leftHandUpdated = true;
}
if (handState == null)
continue;
NRGestureType gestureType = NRGestureType.NR_GESTURE_TYPE_UNKNOWN;
NativeApi.NRHandStateGetGestureType(hand_state_handle, ref gestureType);
UInt32 handJointCount = 0;
NativeApi.NRHandStateGetHandJointCount(hand_state_handle, ref handJointCount);
//NativeApi.NRHandStateGetConfidence(hand_state_handle, ref handState.confidence);
handState.isTracked = true;
handState.pointerPoseValid = true;
handState.currentGesture = GetMappedGesture(gestureType);
for (UInt32 j = 0; j < handJointCount; j++)
{
UInt64 hand_joint_state_handle = 0;
if (NativeApi.NRHandJointStateCreate(hand_state_handle, j, ref hand_joint_state_handle) == NativeResult.Success)
{
NRHandJointType handJointType = NRHandJointType.NR_HAND_JOINT_TYPE_INVALID;
NativeApi.NRHandJointGetHandJointType(hand_joint_state_handle, ref handJointType);
NativeMat4f handJointPose = new NativeMat4f(Matrix4x4.identity);
NativeApi.NRHandJointGetHandJointPose(hand_joint_state_handle, ref handJointPose);
HandJointID handJointID;
if (m_JointMapping.TryGetValue(handJointType, out handJointID))
{
var pose = GetWorldPose(handJointPose);
SetHandJointPose(handState, handJointID, pose);
}
}
}
}
}
public bool Pause()
{
if (m_HandTrackingHandle == 0)
return false;
var result = NativeApi.NRHandTrackingPause(m_HandTrackingHandle);
NativeErrorListener.Check(result, this, "Pause");
return result == NativeResult.Success;
}
public bool Resume()
{
if (m_HandTrackingHandle == 0)
return false;
var result = NativeApi.NRHandTrackingResume(m_HandTrackingHandle);
NativeErrorListener.Check(result, this, "Resume");
return result == NativeResult.Success;
}
public bool Stop()
{
if (m_HandTrackingHandle == 0)
return false;
var result = NativeApi.NRHandTrackingStop(m_HandTrackingHandle);
NativeErrorListener.Check(result, this, "Stop");
return result == NativeResult.Success;
}
public bool Destroy()
{
if (m_HandTrackingHandle == 0)
return false;
var result = NativeApi.NRHandTrackingDestroy(m_HandTrackingHandle);
NativeErrorListener.Check(result, this, "Destroy");
return result == NativeResult.Success;
}
private bool TryUpdateHandTracking()
{
var result = NativeApi.NRHandTrackingUpdate(m_HandTrackingHandle);
return result == NativeResult.Success;
}
private bool TryCreateTrackingDataHandle()
{
var result = NativeApi.NRHandTrackingDataCreate(m_HandTrackingHandle, ref m_TrackingDataHandle);
return result == NativeResult.Success;
}
private bool TryAcquireHandTrackingDataHandle(UInt64 timestamp)
{
var result = NativeApi.NRAcquireHandTrackingData(m_HandTrackingHandle, timestamp, ref m_TrackingDataHandle);
return result == NativeResult.Success;
}
private HandEnum GetMappedHandEnum(NRHandType handType)
{
switch (handType)
{
case NRHandType.NR_HAND_TYPE_LEFT:
return HandEnum.LeftHand;
case NRHandType.NR_HAND_TYPE_RIGHT:
return HandEnum.RightHand;
default:
break;
}
return HandEnum.None;
}
private HandGesture GetMappedGesture(NRGestureType gestureType)
{
switch (gestureType)
{
case NRGestureType.NR_GESTURE_TYPE_OPEN_HAND:
return HandGesture.OpenHand;
case NRGestureType.NR_GESTURE_TYPE_GRAB:
return HandGesture.Grab;
case NRGestureType.NR_GESTURE_TYPE_PINCH:
return HandGesture.Pinch;
case NRGestureType.NR_GESTURE_TYPE_POINT:
return HandGesture.Point;
case NRGestureType.NR_GESTURE_TYPE_VICTORY:
return HandGesture.Victory;
case NRGestureType.NR_GESTURE_TYPE_CALL:
return HandGesture.Call;
case NRGestureType.NR_GESTURE_TYPE_SYSTEM:
return HandGesture.System;
default:
break;
}
return HandGesture.None;
}
private void SetHandJointPose(HandState handState, HandJointID jointID, Pose pose)
{
if (handState.jointsPoseDict.ContainsKey(jointID))
{
handState.jointsPoseDict[jointID] = pose;
}
else
{
handState.jointsPoseDict.Add(jointID, pose);
}
}
private Pose GetWorldPose(NativeMat4f jointPose)
{
if (CameraRigTransform == null)
{
return Pose.identity;
}
Pose unitypose;
ConversionUtility.ApiPoseToUnityPose(jointPose, out unitypose);
return ConversionUtility.ApiWorldToUnityWorld(unitypose);
}
private partial struct NativeApi
{
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingCreate(ref UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingStart(UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingPause(UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingResume(UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingStop(UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingDestroy(UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingGetAvailableHandJoint(UInt64 hand_tracking_handle, ref UInt64 out_available_hand_joint_type_mask);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingGetAvailableGestureType(UInt64 hand_tracking_handle, ref UInt64 out_available_gesture_type_mask);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingGetSupportedFunctions(UInt64 hand_tracking_handle, ref UInt64 out_supported_function_mask);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingUpdate(UInt64 hand_tracking_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingDataCreate(UInt64 hand_tracking_handle, ref UInt64 out_hand_tracking_data_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRAcquireHandTrackingData(UInt64 hand_tracking_handle, UInt64 timestamp, ref UInt64 out_hand_tracking_data_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingDataDestroy(UInt64 hand_tracking_data_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingDataGetHMDTimeNanos(UInt64 hand_tracking_data_handle, ref UInt64 out_hmd_time_nanos);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandTrackingDataGetHandsCount(UInt64 hand_tracking_data_handle, ref UInt32 out_hand_count);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandStateCreate(UInt64 hand_tracking_data_handle, UInt32 hand_index, ref UInt64 out_hand_state_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandStateDestroy(UInt64 hand_state_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandStateGetHandType(UInt64 hand_state_handle, ref NRHandType out_hand_type);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandStateGetGestureType(UInt64 hand_state_handle, ref NRGestureType out_gesture_type);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandStateIsTracked(UInt64 hand_state_handle, ref bool out_is_tracked);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandStateGetHandJointCount(UInt64 hand_state_handle, ref UInt32 out_hand_joint_count);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandJointStateCreate(UInt64 hand_state_handle, UInt32 hand_joint_index, ref UInt64 out_hand_joint_state_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandJointStateDestroy(UInt64 hand_joint_state_handle);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandJointGetHandJointType(UInt64 hand_joint_state_handle, ref NRHandJointType out_hand_joint_type);
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRHandJointGetHandJointPose(UInt64 hand_joint_state_handle, ref NativeMat4f out_hand_joint_pose);
//[DllImport(NativeConstants.NRNativeLibrary)]
//public static extern NativeResult NRHandStateGetConfidence(UInt64 hand_state_handle, ref float out_confidence);
}
}
}