Skip to content

Commit a5a0c5f

Browse files
author
lawwong
committed
Support ViveHandTracking v0.10
Also move StartDetection to background thread
1 parent aba21f5 commit a5a0c5f

File tree

2 files changed

+157
-55
lines changed

2 files changed

+157
-55
lines changed

Assets/HTC.UnityPlugin/VRModule/Submodules/Editor/ViveHandTrackingSubmoduleEditor.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ public ViveHandTrackingRequirementCollection()
1515
reqTypeNames = new string[] { "ViveHandTracking.GestureInterface", "ViveHandTracking.GestureOption" },
1616
reqFileNames = new string[] { "aristo_interface.dll", "GestureInterface.cs" },
1717
});
18+
19+
Add(new SymbolRequirement()
20+
{
21+
symbol = "VIU_VIVE_HAND_TRACKING_0_10_0_OR_NEWER",
22+
reqFileNames = new string[] { "GestureResultExtension.cs" },
23+
});
24+
1825
}
1926
}
2027
}

Assets/HTC.UnityPlugin/VRModule/Submodules/ViveHandTrackingSubmodule.cs

Lines changed: 150 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using UnityEngine;
55
using System.Runtime.InteropServices;
66
using System;
7+
using System.Collections;
8+
using HTC.UnityPlugin.LiteCoroutineSystem;
79
#if VIU_VIVE_HAND_TRACKING
810
using ViveHandTracking;
911
#endif
@@ -16,20 +18,20 @@ public class ViveHandTrackingSubmodule : VRModule.SubmoduleBase
1618
private struct HandResultData
1719
{
1820
public bool isConnected;
19-
public Vector3[] joints;
20-
public GestureType gesture;
21-
public float confidence;
22-
public float pinchLevel;
21+
public GestureResult rawData;
2322
}
2423

24+
private static readonly string LOG_PREFIX = "[" + typeof(ViveHandTrackingSubmodule).Name + "] ";
2525
private const int RETRY_COUNT = 5;
2626
private const float RETRY_INTERVAL = 1f;
2727
private static readonly int sizeofGestureResult = Marshal.SizeOf(typeof(GestureResult));
2828

2929
private GestureOption option = new GestureOption();
3030
private bool isStarted;
3131
private int retryCount;
32-
private float nextRetryTime;
32+
private WaitForTicks retryInterval = WaitForTicks.Seconds(RETRY_INTERVAL);
33+
private LiteCoroutine startDetectionCoroutine;
34+
private LiteTask startDetectionTask = new LiteTask();
3335

3436
private int lastResultFrame;
3537
private HandResultData leftResult;
@@ -42,61 +44,75 @@ private struct HandResultData
4244
protected override void OnActivated()
4345
{
4446
retryCount = RETRY_COUNT;
45-
nextRetryTime = 0f;
4647
GestureInterface.UseExternalTransform(true);
4748
}
4849

4950
protected override void OnDeactivated()
5051
{
5152
GestureInterface.StopGestureDetection();
53+
startDetectionTask.Cancel();
5254
}
5355

5456
public override uint GetRightHandedIndex() { return rightDeviceIndex; }
5557

5658
public override uint GetLeftHandedIndex() { return leftDeviceIndex; }
5759

58-
protected override void OnUpdateDeviceConnectionAndPoses()
60+
private IEnumerator StartDetectionCoroutine()
5961
{
60-
// try start engine detection
61-
if (!isStarted)
62+
while (true)
6263
{
63-
var now = Time.unscaledTime;
64-
if (now >= nextRetryTime && retryCount >= 0)
65-
{
66-
--retryCount;
67-
nextRetryTime = now + RETRY_INTERVAL;
64+
var error = GestureInterface.StartGestureDetection(option);
6865

69-
var error = GestureInterface.StartGestureDetection(option);
66+
lock (this)
67+
{
7068
switch (error)
7169
{
7270
case GestureFailure.None:
7371
retryCount = RETRY_COUNT;
7472
lastResultFrame = -1;
7573
isStarted = true;
76-
Debug.Log("[ViveHandTrackingSubmodule] StartGestureDetection");
74+
Debug.Log(LOG_PREFIX + "StartGestureDetection");
7775
break;
7876
case GestureFailure.Camera:
7977
--retryCount;
80-
nextRetryTime = now + RETRY_INTERVAL;
8178
if (retryCount >= 0)
8279
{
83-
Debug.LogWarning("[ViveHandTrackingSubmodule] StartGestureDetection fail. Front camera function not found. retrying...");
80+
Debug.LogWarning(LOG_PREFIX + "StartGestureDetection fail. Front camera function not found. retrying(" + (retryCount + 1) + ")...");
8481
}
8582
else
8683
{
87-
Debug.LogWarning("[ViveHandTrackingSubmodule] StartGestureDetection fail. Front camera function not found.");
84+
Debug.LogWarning(LOG_PREFIX + "StartGestureDetection fail. Front camera function not found.");
8885
}
8986
break;
9087
default:
9188
retryCount = 0;
92-
Debug.LogWarning("[ViveHandTrackingSubmodule] StartGestureDetection fail. error:" + error);
89+
Debug.LogWarning(LOG_PREFIX + "StartGestureDetection fail. error:" + error);
9390
break;
9491

9592
}
93+
94+
if (retryCount <= 0 || isStarted) { yield break; }
9695
}
96+
97+
yield return retryInterval;
9798
}
99+
}
98100

99-
if (!isStarted) { return; }
101+
protected override void OnUpdateDeviceConnectionAndPoses()
102+
{
103+
lock (this)
104+
{
105+
if (!isStarted && retryCount > 0 && startDetectionTask.IsDone)
106+
{
107+
// try start engine detection
108+
LiteCoroutine.StartCoroutine(ref startDetectionCoroutine, startDetectionTask.RestartTask(StartDetectionCoroutine()));
109+
}
110+
111+
if (!isStarted) { return; }
112+
}
113+
114+
var hmdPose = VRModule.GetDeviceState(VRModule.HMD_DEVICE_INDEX).pose;
115+
GestureInterface.SetCameraTransform(hmdPose.pos, hmdPose.rot);
100116

101117
// fetch raw data from engine
102118
IntPtr resultPtr;
@@ -109,7 +125,7 @@ protected override void OnUpdateDeviceConnectionAndPoses()
109125
isStarted = false;
110126
return;
111127
}
112-
else if (resultFrame < lastResultFrame)
128+
else if (resultFrame <= lastResultFrame)
113129
{
114130
// skip frame
115131
return;
@@ -128,21 +144,15 @@ protected override void OnUpdateDeviceConnectionAndPoses()
128144
leftResult = new HandResultData()
129145
{
130146
isConnected = true,
131-
joints = result.points,
132-
gesture = result.gesture,
133-
confidence = result.confidence,
134-
pinchLevel = result.pinchLevel,
147+
rawData = result,
135148
};
136149
}
137150
else
138151
{
139152
rightResult = new HandResultData()
140153
{
141154
isConnected = true,
142-
joints = result.points,
143-
gesture = result.gesture,
144-
confidence = result.confidence,
145-
pinchLevel = result.pinchLevel,
155+
rawData = result,
146156
};
147157
}
148158
#if NET_4_6
@@ -184,7 +194,7 @@ private void UpdateDeviceConnectionAndPoses(ref HandResultData resultData, ref u
184194

185195
currState.isConnected = true;
186196
currState.isPoseValid = true;
187-
UpdateDeviceJoints(currState, resultData.joints, isLeft);
197+
UpdateDeviceJoints(currState, ref resultData, isLeft);
188198
}
189199
else
190200
{
@@ -205,6 +215,22 @@ protected override void OnUpdateDeviceInput()
205215
UpdateDeviceInput(ref rightResult, rightDeviceIndex);
206216
}
207217

218+
#if VIU_VIVE_HAND_TRACKING_0_10_0_OR_NEWER
219+
[StructLayout(LayoutKind.Sequential)]
220+
private struct GestureResult
221+
{
222+
[MarshalAs(UnmanagedType.I1)]
223+
public bool isLeft;
224+
public Vector3 position;
225+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)]
226+
public Vector3[] points;
227+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)]
228+
public Quaternion[] rotations;
229+
public GestureType gesture;
230+
public float confidence;
231+
public PinchInfo pinch;
232+
}
233+
208234
private void UpdateDeviceInput(ref HandResultData resultData, uint index)
209235
{
210236
if (!resultData.isConnected) { return; }
@@ -214,12 +240,12 @@ private void UpdateDeviceInput(ref HandResultData resultData, uint index)
214240

215241
EnsureValidDeviceState(index, out prevState, out currState);
216242

217-
var pinched = resultData.pinchLevel >= 0.95f;
218-
var gFist = resultData.gesture == GestureType.Fist && resultData.confidence > 0.1f;
219-
var gFive = resultData.gesture == GestureType.Five && resultData.confidence > 0.1f;
220-
var gOK = resultData.gesture == GestureType.OK && resultData.confidence > 0.1f;
221-
var gLike = resultData.gesture == GestureType.Like && resultData.confidence > 0.1f;
222-
var gPoint = resultData.gesture == GestureType.Point && resultData.confidence > 0.1f;
243+
var pinched = resultData.rawData.pinch.pinchLevel >= 0.95f;
244+
var gFist = resultData.rawData.gesture == GestureType.Fist && resultData.rawData.confidence > 0.1f;
245+
var gFive = resultData.rawData.gesture == GestureType.Five && resultData.rawData.confidence > 0.1f;
246+
var gOK = resultData.rawData.gesture == GestureType.OK && resultData.rawData.confidence > 0.1f;
247+
var gLike = resultData.rawData.gesture == GestureType.Like && resultData.rawData.confidence > 0.1f;
248+
var gPoint = resultData.rawData.gesture == GestureType.Point && resultData.rawData.confidence > 0.1f;
223249
currState.SetButtonPress(VRModuleRawButton.GestureIndexPinch, pinched);
224250
currState.SetButtonTouch(VRModuleRawButton.GestureIndexPinch, pinched);
225251
currState.SetButtonPress(VRModuleRawButton.GestureFist, gFist);
@@ -234,13 +260,93 @@ private void UpdateDeviceInput(ref HandResultData resultData, uint index)
234260
currState.SetButtonTouch(VRModuleRawButton.GestureIndexUp, gPoint);
235261
currState.SetButtonPress(VRModuleRawButton.Grip, gFist);
236262
currState.SetButtonTouch(VRModuleRawButton.Grip, gFist);
237-
currState.SetAxisValue(VRModuleRawAxis.Trigger, resultData.pinchLevel);
263+
currState.SetAxisValue(VRModuleRawAxis.Trigger, resultData.rawData.pinch.pinchLevel);
238264
}
239265

240-
private static void UpdateDeviceJoints(IVRModuleDeviceStateRW state, Vector3[] rawJoints, bool isLeft)
266+
private static readonly Quaternion rotOffset = Quaternion.Inverse(Quaternion.LookRotation(Vector3.down, Vector3.forward));
267+
private static void UpdateDeviceJoints(IVRModuleDeviceStateRW state, ref HandResultData resultData, bool isLeft)
241268
{
242-
var hmdPose = VRModule.GetDeviceState(VRModule.HMD_DEVICE_INDEX).pose;
243-
GestureInterface.SetCameraTransform(hmdPose.pos, hmdPose.rot);
269+
var joints = resultData.rawData.points;
270+
var rotations = resultData.rawData.rotations;
271+
272+
state.pose = new RigidPose(joints[0], rotations[0] * rotOffset);
273+
274+
state.handJoints[HandJointName.Wrist] = new JointPose(new RigidPose(joints[0], rotations[0] * rotOffset));
275+
276+
state.handJoints[HandJointName.ThumbMetacarpal] = new JointPose(new RigidPose(joints[1], rotations[1] * rotOffset));
277+
state.handJoints[HandJointName.ThumbProximal] = new JointPose(new RigidPose(joints[2], rotations[2] * rotOffset));
278+
state.handJoints[HandJointName.ThumbDistal] = new JointPose(new RigidPose(joints[3], rotations[3] * rotOffset));
279+
state.handJoints[HandJointName.ThumbTip] = new JointPose(new RigidPose(joints[4], rotations[4] * rotOffset));
280+
281+
state.handJoints[HandJointName.IndexProximal] = new JointPose(new RigidPose(joints[5], rotations[5] * rotOffset));
282+
state.handJoints[HandJointName.IndexIntermediate] = new JointPose(new RigidPose(joints[6], rotations[6] * rotOffset));
283+
state.handJoints[HandJointName.IndexDistal] = new JointPose(new RigidPose(joints[7], rotations[7] * rotOffset));
284+
state.handJoints[HandJointName.IndexTip] = new JointPose(new RigidPose(joints[8], rotations[8] * rotOffset));
285+
286+
state.handJoints[HandJointName.MiddleProximal] = new JointPose(new RigidPose(joints[9], rotations[9] * rotOffset));
287+
state.handJoints[HandJointName.MiddleIntermediate] = new JointPose(new RigidPose(joints[10], rotations[10] * rotOffset));
288+
state.handJoints[HandJointName.MiddleDistal] = new JointPose(new RigidPose(joints[11], rotations[11] * rotOffset));
289+
state.handJoints[HandJointName.MiddleTip] = new JointPose(new RigidPose(joints[12], rotations[12] * rotOffset));
290+
291+
state.handJoints[HandJointName.RingProximal] = new JointPose(new RigidPose(joints[13], rotations[13] * rotOffset));
292+
state.handJoints[HandJointName.RingIntermediate] = new JointPose(new RigidPose(joints[14], rotations[14] * rotOffset));
293+
state.handJoints[HandJointName.RingDistal] = new JointPose(new RigidPose(joints[15], rotations[15] * rotOffset));
294+
state.handJoints[HandJointName.RingTip] = new JointPose(new RigidPose(joints[16], rotations[16] * rotOffset));
295+
296+
state.handJoints[HandJointName.PinkyProximal] = new JointPose(new RigidPose(joints[17], rotations[17] * rotOffset));
297+
state.handJoints[HandJointName.PinkyIntermediate] = new JointPose(new RigidPose(joints[18], rotations[18] * rotOffset));
298+
state.handJoints[HandJointName.PinkyDistal] = new JointPose(new RigidPose(joints[19], rotations[19] * rotOffset));
299+
state.handJoints[HandJointName.PinkyTip] = new JointPose(new RigidPose(joints[20], rotations[20] * rotOffset));
300+
}
301+
#else
302+
[StructLayout(LayoutKind.Sequential)]
303+
private struct GestureResult
304+
{
305+
[MarshalAs(UnmanagedType.I1)]
306+
public bool isLeft;
307+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)]
308+
public Vector3[] points;
309+
public GestureType gesture;
310+
public float confidence;
311+
public float pinchLevel;
312+
}
313+
314+
private void UpdateDeviceInput(ref HandResultData resultData, uint index)
315+
{
316+
if (!resultData.isConnected) { return; }
317+
318+
IVRModuleDeviceState prevState;
319+
IVRModuleDeviceStateRW currState;
320+
321+
EnsureValidDeviceState(index, out prevState, out currState);
322+
323+
var pinched = resultData.rawData.pinchLevel >= 0.95f;
324+
var gFist = resultData.rawData.gesture == GestureType.Fist && resultData.rawData.confidence > 0.1f;
325+
var gFive = resultData.rawData.gesture == GestureType.Five && resultData.rawData.confidence > 0.1f;
326+
var gOK = resultData.rawData.gesture == GestureType.OK && resultData.rawData.confidence > 0.1f;
327+
var gLike = resultData.rawData.gesture == GestureType.Like && resultData.rawData.confidence > 0.1f;
328+
var gPoint = resultData.rawData.gesture == GestureType.Point && resultData.rawData.confidence > 0.1f;
329+
currState.SetButtonPress(VRModuleRawButton.GestureIndexPinch, pinched);
330+
currState.SetButtonTouch(VRModuleRawButton.GestureIndexPinch, pinched);
331+
currState.SetButtonPress(VRModuleRawButton.GestureFist, gFist);
332+
currState.SetButtonTouch(VRModuleRawButton.GestureFist, gFist);
333+
currState.SetButtonPress(VRModuleRawButton.GestureFive, gFive);
334+
currState.SetButtonTouch(VRModuleRawButton.GestureFive, gFive);
335+
currState.SetButtonPress(VRModuleRawButton.GestureOk, gOK);
336+
currState.SetButtonTouch(VRModuleRawButton.GestureOk, gOK);
337+
currState.SetButtonPress(VRModuleRawButton.GestureThumbUp, gLike);
338+
currState.SetButtonTouch(VRModuleRawButton.GestureThumbUp, gLike);
339+
currState.SetButtonPress(VRModuleRawButton.GestureIndexUp, gPoint);
340+
currState.SetButtonTouch(VRModuleRawButton.GestureIndexUp, gPoint);
341+
currState.SetButtonPress(VRModuleRawButton.Grip, gFist);
342+
currState.SetButtonTouch(VRModuleRawButton.Grip, gFist);
343+
currState.SetAxisValue(VRModuleRawAxis.Trigger, resultData.rawData.pinchLevel);
344+
}
345+
346+
private static void UpdateDeviceJoints(IVRModuleDeviceStateRW state, ref HandResultData resultData, bool isLeft)
347+
{
348+
var rawJoints = resultData.rawData.points;
349+
244350
var roomSpaceWrist2index = rawJoints[5] - rawJoints[0];
245351
var roomSpaceWrist2middle = rawJoints[9] - rawJoints[0];
246352
var roomSpaceWrist2pinky = rawJoints[17] - rawJoints[0];
@@ -299,18 +405,7 @@ private static Quaternion CalculateJointRot(Vector3[] joints, int i, int iChild,
299405
var forward = joints[iChild] - joints[i];
300406
return Quaternion.LookRotation(forward, Vector3.Cross(forward, right));
301407
}
302-
303-
[StructLayout(LayoutKind.Sequential)]
304-
private struct GestureResult
305-
{
306-
[MarshalAs(UnmanagedType.I1)]
307-
public bool isLeft;
308-
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)]
309-
public Vector3[] points;
310-
public GestureType gesture;
311-
public float confidence;
312-
public float pinchLevel;
313-
}
408+
#endif
314409

315410
private static class GestureInterface
316411
{
@@ -332,5 +427,5 @@ private static class GestureInterface
332427
internal static extern void SetCameraTransform(Vector3 position, Quaternion rotation);
333428
}
334429
#endif
335-
}
336-
}
430+
}
431+
}

0 commit comments

Comments
 (0)