Skip to content

Commit 4325e84

Browse files
authored
Merge pull request #149 from De-Panther/hand_mesh_support
Support for Generic Hands models from the WebXR Input Profiles
2 parents 9c75443 + ef179df commit 4325e84

File tree

11 files changed

+328
-77
lines changed

11 files changed

+328
-77
lines changed

MainProject/Packages/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
}
1111
],
1212
"dependencies": {
13-
"com.de-panther.webxr-input-profiles-loader": "0.3.5",
13+
"com.de-panther.webxr-input-profiles-loader": "0.3.6",
1414
"com.unity.ide.rider": "2.0.5",
1515
"com.unity.ide.vscode": "1.2.3",
1616
"com.unity.test-framework": "1.1.16",

MainProject/Packages/packages-lock.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"dependencies": {
33
"com.atteneder.gltfast": {
4-
"version": "3.0.2",
4+
"version": "3.2.1",
55
"depth": 1,
66
"source": "registry",
77
"dependencies": {
@@ -21,12 +21,12 @@
2121
}
2222
},
2323
"com.de-panther.webxr-input-profiles-loader": {
24-
"version": "0.3.5",
24+
"version": "0.3.6",
2525
"depth": 0,
2626
"source": "registry",
2727
"dependencies": {
2828
"com.unity.nuget.newtonsoft-json": "2.0.0",
29-
"com.atteneder.gltfast": "3.0.2"
29+
"com.atteneder.gltfast": "3.2.1"
3030
},
3131
"url": "https://package.openupm.com"
3232
},

Packages/webxr-interactions/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Support for Generic Hands models from the WebXR Input Profiles.
10+
11+
### Changed
12+
- Minimum WebXR Input Profiles Loader version 0.3.6.
813

914
## [0.9.0] - 2021-04-16
1015
### Changed

Packages/webxr-interactions/Runtime/Prefabs/WebXRCameraSet.prefab

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ Transform:
283283
m_Children:
284284
- {fileID: 4008237015318879989}
285285
- {fileID: 1218315907877956796}
286+
- {fileID: 2202373014578844308}
286287
m_Father: {fileID: 4545079059221816}
287288
m_RootOrder: 0
288289
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -351,6 +352,7 @@ MonoBehaviour:
351352
useInputProfile: 1
352353
inputProfileObject: {fileID: 1611361787474004}
353354
inputProfileModelParent: {fileID: 1469228564561163144}
355+
inputProfileHandModelParent: {fileID: 3331348236738357118}
354356
--- !u!114 &7185579886917944061
355357
MonoBehaviour:
356358
m_ObjectHideFlags: 0
@@ -496,6 +498,7 @@ Transform:
496498
m_Children:
497499
- {fileID: 3110396931964762061}
498500
- {fileID: 3819867499605581648}
501+
- {fileID: 1956285881968495143}
499502
m_Father: {fileID: 4545079059221816}
500503
m_RootOrder: 1
501504
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -564,6 +567,7 @@ MonoBehaviour:
564567
useInputProfile: 1
565568
inputProfileObject: {fileID: 1611361787474004}
566569
inputProfileModelParent: {fileID: 599836867309221058}
570+
inputProfileHandModelParent: {fileID: 8661450511316122934}
567571
--- !u!114 &1966769163579045322
568572
MonoBehaviour:
569573
m_ObjectHideFlags: 0
@@ -837,6 +841,36 @@ Camera:
837841
m_OcclusionCulling: 1
838842
m_StereoConvergence: 10
839843
m_StereoSeparation: 0.022
844+
--- !u!1 &3331348236738357118
845+
GameObject:
846+
m_ObjectHideFlags: 0
847+
m_CorrespondingSourceObject: {fileID: 0}
848+
m_PrefabInstance: {fileID: 0}
849+
m_PrefabAsset: {fileID: 0}
850+
serializedVersion: 6
851+
m_Component:
852+
- component: {fileID: 2202373014578844308}
853+
m_Layer: 0
854+
m_Name: HandInputModel
855+
m_TagString: Untagged
856+
m_Icon: {fileID: 0}
857+
m_NavMeshLayer: 0
858+
m_StaticEditorFlags: 0
859+
m_IsActive: 1
860+
--- !u!4 &2202373014578844308
861+
Transform:
862+
m_ObjectHideFlags: 0
863+
m_CorrespondingSourceObject: {fileID: 0}
864+
m_PrefabInstance: {fileID: 0}
865+
m_PrefabAsset: {fileID: 0}
866+
m_GameObject: {fileID: 3331348236738357118}
867+
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
868+
m_LocalPosition: {x: 0, y: 0, z: 0}
869+
m_LocalScale: {x: 1, y: 1, z: 1}
870+
m_Children: []
871+
m_Father: {fileID: 4427160273819458}
872+
m_RootOrder: 2
873+
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
840874
--- !u!1 &3858442981242374931
841875
GameObject:
842876
m_ObjectHideFlags: 0
@@ -1043,3 +1077,33 @@ Camera:
10431077
m_OcclusionCulling: 1
10441078
m_StereoConvergence: 10
10451079
m_StereoSeparation: 0.022
1080+
--- !u!1 &8661450511316122934
1081+
GameObject:
1082+
m_ObjectHideFlags: 0
1083+
m_CorrespondingSourceObject: {fileID: 0}
1084+
m_PrefabInstance: {fileID: 0}
1085+
m_PrefabAsset: {fileID: 0}
1086+
serializedVersion: 6
1087+
m_Component:
1088+
- component: {fileID: 1956285881968495143}
1089+
m_Layer: 0
1090+
m_Name: HandInputModel
1091+
m_TagString: Untagged
1092+
m_Icon: {fileID: 0}
1093+
m_NavMeshLayer: 0
1094+
m_StaticEditorFlags: 0
1095+
m_IsActive: 1
1096+
--- !u!4 &1956285881968495143
1097+
Transform:
1098+
m_ObjectHideFlags: 0
1099+
m_CorrespondingSourceObject: {fileID: 0}
1100+
m_PrefabInstance: {fileID: 0}
1101+
m_PrefabAsset: {fileID: 0}
1102+
m_GameObject: {fileID: 8661450511316122934}
1103+
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
1104+
m_LocalPosition: {x: 0, y: 0, z: 0}
1105+
m_LocalScale: {x: 1, y: 1, z: 1}
1106+
m_Children: []
1107+
m_Father: {fileID: 4446684710817404}
1108+
m_RootOrder: 2
1109+
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

Packages/webxr-interactions/Runtime/Scripts/ControllerInteraction.cs

Lines changed: 124 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,19 @@ public class ControllerInteraction : MonoBehaviour
3030

3131
private GameObject[] handJointsVisuals = new GameObject[25];
3232
private Dictionary<int, Transform> handJoints = new Dictionary<int, Transform>();
33+
public GameObject inputProfileHandModelParent;
3334

3435
#if WEBXR_INPUT_PROFILES
3536
private InputProfileLoader inputProfileLoader;
3637
private InputProfileModel inputProfileModel;
3738
private bool hasProfileList = false;
3839
private bool loadedModel = false;
3940
private string loadedProfile = null;
41+
42+
private InputProfileModel inputProfileHandModel;
43+
private bool loadedHandModel = false;
44+
private string loadedHandProfile = null;
45+
private Dictionary<int, Transform> handModelJoints = new Dictionary<int, Transform>();
4046
#endif
4147

4248
private void Awake()
@@ -206,6 +212,27 @@ private void SetHandJointsVisible(bool visible)
206212
{
207213
handJointsVisible = visible;
208214
Drop();
215+
#if WEBXR_INPUT_PROFILES
216+
// We want to use WebXR Input Profiles
217+
if (visible && useInputProfile)
218+
{
219+
if (inputProfileHandModel != null && loadedHandModel)
220+
{
221+
// There's a loaded Input Profile Model
222+
inputProfileHandModelParent.SetActive(true);
223+
return;
224+
}
225+
else if (inputProfileHandModel == null)
226+
{
227+
// There's no loaded Input Profile Model and it's not in loading process
228+
LoadHandInputProfile();
229+
}
230+
}
231+
else
232+
{
233+
inputProfileHandModelParent.SetActive(false);
234+
}
235+
#endif
209236
foreach (var visual in handJointsVisuals)
210237
{
211238
visual?.SetActive(visible);
@@ -224,36 +251,48 @@ private void OnHandUpdate(WebXRHandData handData)
224251
}
225252
Quaternion rotationOffset = Quaternion.Inverse(handData.joints[0].rotation);
226253

227-
for (int i = 0; i <= WebXRHandData.LITTLE_PHALANX_TIP; i++)
254+
#if WEBXR_INPUT_PROFILES
255+
if (useInputProfile && loadedHandModel)
228256
{
229-
if (handData.joints[i].enabled)
257+
for (int i = 0; i <= (int)WebXRHandJoint.pinky_finger_tip; i++)
230258
{
231-
if (handJoints.ContainsKey(i))
259+
if (handModelJoints.ContainsKey(i))
232260
{
233-
handJoints[i].localPosition = rotationOffset * (handData.joints[i].position - handData.joints[0].position);
234-
handJoints[i].localRotation = rotationOffset * handData.joints[i].rotation;
235-
if (handData.joints[i].radius != handJoints[i].localScale.x && handData.joints[i].radius > 0)
236-
{
237-
handJoints[i].localScale = new Vector3(handData.joints[i].radius, handData.joints[i].radius, handData.joints[i].radius);
238-
}
261+
handModelJoints[i].localPosition = rotationOffset * (handData.joints[i].position - handData.joints[0].position);
262+
handModelJoints[i].localRotation = rotationOffset * handData.joints[i].rotation;
263+
}
264+
}
265+
return;
266+
}
267+
#endif
268+
269+
for (int i = 0; i <= (int)WebXRHandJoint.pinky_finger_tip; i++)
270+
{
271+
if (handJoints.ContainsKey(i))
272+
{
273+
handJoints[i].localPosition = rotationOffset * (handData.joints[i].position - handData.joints[0].position);
274+
handJoints[i].localRotation = rotationOffset * handData.joints[i].rotation;
275+
if (handData.joints[i].radius != handJoints[i].localScale.x && handData.joints[i].radius > 0)
276+
{
277+
handJoints[i].localScale = new Vector3(handData.joints[i].radius, handData.joints[i].radius, handData.joints[i].radius);
278+
}
279+
}
280+
else
281+
{
282+
var clone = Instantiate(handJointPrefab,
283+
rotationOffset * (handData.joints[i].position - handData.joints[0].position),
284+
rotationOffset * handData.joints[i].rotation,
285+
transform);
286+
if (handData.joints[i].radius > 0f)
287+
{
288+
clone.localScale = new Vector3(handData.joints[i].radius, handData.joints[i].radius, handData.joints[i].radius);
239289
}
240290
else
241291
{
242-
var clone = Instantiate(handJointPrefab,
243-
rotationOffset * (handData.joints[i].position - handData.joints[0].position),
244-
rotationOffset * handData.joints[i].rotation,
245-
transform);
246-
if (handData.joints[i].radius > 0f)
247-
{
248-
clone.localScale = new Vector3(handData.joints[i].radius, handData.joints[i].radius, handData.joints[i].radius);
249-
}
250-
else
251-
{
252-
clone.localScale = new Vector3(0.005f, 0.005f, 0.005f);
253-
}
254-
handJoints.Add(i, clone);
255-
handJointsVisuals[i] = clone.gameObject;
292+
clone.localScale = new Vector3(0.005f, 0.005f, 0.005f);
256293
}
294+
handJoints.Add(i, clone);
295+
handJointsVisuals[i] = clone.gameObject;
257296
}
258297
}
259298
}
@@ -284,6 +323,13 @@ private void LoadInputProfile()
284323
}
285324
}
286325

326+
private void LoadHandInputProfile()
327+
{
328+
// Start loading the generic hand profile
329+
loadedHandProfile = "generic-hand";
330+
inputProfileLoader.LoadProfile(new string[] {loadedHandProfile}, OnHandProfileLoaded);
331+
}
332+
287333
private void OnProfileLoaded(bool success)
288334
{
289335
if (success)
@@ -293,6 +339,15 @@ private void OnProfileLoaded(bool success)
293339
// Nothing to do if profile didn't load
294340
}
295341

342+
private void OnHandProfileLoaded(bool success)
343+
{
344+
if (success)
345+
{
346+
LoadHandInputModel();
347+
}
348+
// Nothing to do if profile didn't load
349+
}
350+
296351
private void LoadInputModel()
297352
{
298353
inputProfileModel = inputProfileLoader.LoadModelForHand(
@@ -306,6 +361,14 @@ private void LoadInputModel()
306361
}
307362
}
308363

364+
private void LoadHandInputModel()
365+
{
366+
inputProfileHandModel = inputProfileLoader.LoadModelForHand(
367+
loadedHandProfile,
368+
(InputProfileLoader.Handedness)controller.hand,
369+
HandleHandModelLoaded);
370+
}
371+
309372
private void HandleModelLoaded(bool success)
310373
{
311374
loadedModel = success;
@@ -333,6 +396,44 @@ private void HandleModelLoaded(bool success)
333396
}
334397
}
335398

399+
private void HandleHandModelLoaded(bool success)
400+
{
401+
loadedHandModel = success;
402+
if (loadedHandModel)
403+
{
404+
// Set parent only after successful loading, to not interupt loading in case of disabled object
405+
var inputProfileModelTransform = inputProfileHandModel.transform;
406+
inputProfileModelTransform.SetParent(inputProfileHandModelParent.transform);
407+
inputProfileModelTransform.localPosition = Vector3.zero;
408+
inputProfileModelTransform.localRotation = Quaternion.identity;
409+
inputProfileModelTransform.localScale = Vector3.one;
410+
for (int i = 0; i <= (int)WebXRHandJoint.pinky_finger_tip; i++)
411+
{
412+
handModelJoints.Add(i, inputProfileHandModel.GetChildTransform(((WebXRHandJoint)i).ToString().Replace('_','-')));
413+
// It took at least one frame with hand data, there should be hand joint transform
414+
if (handJoints.ContainsKey(i))
415+
{
416+
handModelJoints[i].SetPositionAndRotation(handJoints[i].position, handJoints[i].rotation);
417+
var collider = handModelJoints[i].gameObject.AddComponent<SphereCollider>();
418+
collider.radius = handJoints[i].localScale.x;
419+
collider.isTrigger = true;
420+
}
421+
}
422+
if (handJointsVisible)
423+
{
424+
inputProfileHandModelParent.SetActive(true);
425+
foreach (var visual in handJointsVisuals)
426+
{
427+
visual?.SetActive(false);
428+
}
429+
}
430+
}
431+
else
432+
{
433+
Destroy(inputProfileHandModel.gameObject);
434+
}
435+
}
436+
336437
private void UpdateModelInput()
337438
{
338439
for (int i = 0; i < 6; i++)

Packages/webxr-interactions/Runtime/Scripts/WebXR.Interactions.asmdef

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"versionDefines": [
1515
{
1616
"name": "com.de-panther.webxr-input-profiles-loader",
17-
"expression": "0.3.5",
17+
"expression": "0.3.6",
1818
"define": "WEBXR_INPUT_PROFILES"
1919
}
2020
],

0 commit comments

Comments
 (0)