Skip to content

Commit 0272f92

Browse files
authored
Use fillPoses and fillJointRadii instead of getJointPose (#5298)
* Don't offset reference space for hand-tracking-controls * Use fillPoses and fillJointRadii once per tick in hand-tracking-controls * Update hand-tracking-controls test to call tick before detectPinch --------- Co-authored-by: Noeri Huisman <mrxz@users.noreply.github.com>
1 parent 61bff0d commit 0272f92

File tree

2 files changed

+76
-75
lines changed

2 files changed

+76
-75
lines changed

‎src/components/hand-tracking-controls.js‎

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* global THREE, XRRigidTransform */
1+
/* global THREE */
22
var registerComponent = require('../core/component').registerComponent;
33
var bind = require('../utils/bind');
44

@@ -36,6 +36,9 @@ var JOINTS = [
3636
'pinky-finger-tip'
3737
];
3838

39+
var THUMB_TIP_INDEX = 4;
40+
var INDEX_TIP_INDEX = 9;
41+
3942
var PINCH_START_DISTANCE = 0.015;
4043
var PINCH_END_DISTANCE = 0.03;
4144
var PINCH_POSITION_INTERPOLATION = 0.5;
@@ -82,6 +85,10 @@ module.exports.Component = registerComponent('hand-tracking-controls', {
8285
this.pinchEventDetail = {position: new THREE.Vector3()};
8386
this.indexTipPosition = new THREE.Vector3();
8487

88+
this.hasPoses = false;
89+
this.jointPoses = new Float32Array(16 * JOINTS.length);
90+
this.jointRadii = new Float32Array(JOINTS.length);
91+
8592
this.bindMethods();
8693

8794
this.updateReferenceSpace = this.updateReferenceSpace.bind(this);
@@ -96,7 +103,7 @@ module.exports.Component = registerComponent('hand-tracking-controls', {
96103
if (!xrSession) { return; }
97104
var referenceSpaceType = self.el.sceneEl.systems.webxr.sessionReferenceSpaceType;
98105
xrSession.requestReferenceSpace(referenceSpaceType).then(function (referenceSpace) {
99-
self.referenceSpace = referenceSpace.getOffsetReferenceSpace(new XRRigidTransform({x: 0, y: 1.5, z: 0}));
106+
self.referenceSpace = referenceSpace;
100107
}).catch(function (error) {
101108
self.el.sceneEl.systems.webxr.warnIfFeatureNotRequested(referenceSpaceType, 'tracked-controls-webxr uses reference space ' + referenceSpaceType);
102109
throw error;
@@ -121,11 +128,17 @@ module.exports.Component = registerComponent('hand-tracking-controls', {
121128
var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;
122129
var frame = sceneEl.frame;
123130
var trackedControlsWebXR = this.el.components['tracked-controls-webxr'];
124-
if (!controller || !frame || !trackedControlsWebXR) { return; }
131+
var referenceSpace = this.referenceSpace;
132+
if (!controller || !frame || !referenceSpace || !trackedControlsWebXR) { return; }
133+
this.hasPoses = false;
125134
if (controller.hand) {
126135
this.el.object3D.position.set(0, 0, 0);
127136
this.el.object3D.rotation.set(0, 0, 0);
128-
if (frame.getJointPose) { this.updateHandModel(); }
137+
138+
this.hasPoses = frame.fillPoses(controller.hand.values(), referenceSpace, this.jointPoses) &&
139+
frame.fillJointRadii(controller.hand.values(), this.jointRadii);
140+
141+
this.updateHandModel();
129142
this.detectGesture();
130143
}
131144
},
@@ -148,47 +161,44 @@ module.exports.Component = registerComponent('hand-tracking-controls', {
148161
return null;
149162
},
150163

151-
updateHandMeshModel: function () {
152-
var frame = this.el.sceneEl.frame;
153-
var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;
154-
var referenceSpace = this.referenceSpace;
155-
156-
if (!controller || !this.mesh || !referenceSpace) { return; }
157-
this.mesh.visible = false;
158-
for (var inputjoint of controller.hand.values()) {
159-
var bone;
160-
var jointPose;
161-
var jointTransform;
162-
jointPose = frame.getJointPose(inputjoint, referenceSpace);
163-
bone = this.getBone(inputjoint.jointName);
164-
if (bone != null && jointPose) {
165-
jointTransform = jointPose.transform;
166-
this.mesh.visible = true;
167-
bone.position.copy(jointTransform.position);
168-
bone.quaternion.copy(jointTransform.orientation);
164+
updateHandMeshModel: (function () {
165+
var jointPose = new THREE.Matrix4();
166+
return function () {
167+
var jointPoses = this.jointPoses;
168+
var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;
169+
var i = 0;
170+
171+
if (!controller || !this.mesh) { return; }
172+
this.mesh.visible = false;
173+
if (!this.hasPoses) { return; }
174+
for (var inputjoint of controller.hand.values()) {
175+
var bone = this.getBone(inputjoint.jointName);
176+
if (bone != null) {
177+
this.mesh.visible = true;
178+
jointPose.fromArray(jointPoses, i * 16);
179+
bone.position.setFromMatrixPosition(jointPose);
180+
bone.quaternion.setFromRotationMatrix(jointPose);
181+
}
182+
i++;
169183
}
170-
}
171-
},
184+
};
185+
})(),
172186

173187
updateHandDotsModel: function () {
174-
var frame = this.el.sceneEl.frame;
188+
var jointPoses = this.jointPoses;
189+
var jointRadii = this.jointRadii;
175190
var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;
176-
var trackedControlsWebXR = this.el.components['tracked-controls-webxr'];
177-
var referenceSpace = trackedControlsWebXR.system.referenceSpace;
178191
var jointEl;
179192
var object3D;
180-
var jointPose;
181-
var i = 0;
182193

183-
for (var inputjoint of controller.hand.values()) {
184-
jointEl = this.jointEls[i++];
194+
for (var i = 0; i < controller.hand.size; i++) {
195+
jointEl = this.jointEls[i];
185196
object3D = jointEl.object3D;
186-
jointPose = frame.getJointPose(inputjoint, referenceSpace);
187-
jointEl.object3D.visible = !!jointPose;
188-
if (!jointPose) { continue; }
189-
object3D.matrix.elements = jointPose.transform.matrix;
197+
jointEl.object3D.visible = this.hasPoses;
198+
if (!this.hasPoses) { continue; }
199+
object3D.matrix.fromArray(jointPoses, i * 16);
190200
object3D.matrix.decompose(object3D.position, object3D.rotation, object3D.scale);
191-
jointEl.setAttribute('scale', {x: jointPose.radius, y: jointPose.radius, z: jointPose.radius});
201+
jointEl.setAttribute('scale', {x: jointRadii[i], y: jointRadii[i], z: jointRadii[i]});
192202
}
193203
},
194204

@@ -198,47 +208,32 @@ module.exports.Component = registerComponent('hand-tracking-controls', {
198208

199209
detectPinch: (function () {
200210
var thumbTipPosition = new THREE.Vector3();
211+
var jointPose = new THREE.Matrix4();
201212
return function () {
202-
var frame = this.el.sceneEl.frame;
203213
var indexTipPosition = this.indexTipPosition;
204-
var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;
205-
var trackedControlsWebXR = this.el.components['tracked-controls-webxr'];
206-
var referenceSpace = this.referenceSpace || trackedControlsWebXR.system.referenceSpace;
207-
var indexTip = controller.hand.get('index-finger-tip');
208-
var thumbTip = controller.hand.get('thumb-tip');
209-
if (!indexTip ||
210-
!thumbTip) { return; }
211-
var indexTipPose = frame.getJointPose(indexTip, referenceSpace);
212-
var thumbTipPose = frame.getJointPose(thumbTip, referenceSpace);
214+
if (!this.hasPoses) { return; }
213215

214-
if (!indexTipPose || !thumbTipPose) { return; }
215-
216-
thumbTipPosition.copy(thumbTipPose.transform.position);
217-
indexTipPosition.copy(indexTipPose.transform.position);
216+
thumbTipPosition.setFromMatrixPosition(jointPose.fromArray(this.jointPoses, THUMB_TIP_INDEX * 16));
217+
indexTipPosition.setFromMatrixPosition(jointPose.fromArray(this.jointPoses, INDEX_TIP_INDEX * 16));
218218

219219
var distance = indexTipPosition.distanceTo(thumbTipPosition);
220220

221221
if (distance < PINCH_START_DISTANCE && this.isPinched === false) {
222222
this.isPinched = true;
223223
this.pinchEventDetail.position.copy(indexTipPosition).lerp(thumbTipPosition, PINCH_POSITION_INTERPOLATION);
224-
this.pinchEventDetail.position.y += 1.5;
225224
this.el.emit('pinchstarted', this.pinchEventDetail);
226225
}
227226

228227
if (distance > PINCH_END_DISTANCE && this.isPinched === true) {
229228
this.isPinched = false;
230229
this.pinchEventDetail.position.copy(indexTipPosition).lerp(thumbTipPosition, PINCH_POSITION_INTERPOLATION);
231-
this.pinchEventDetail.position.y += 1.5;
232230
this.el.emit('pinchended', this.pinchEventDetail);
233231
}
234232

235233
if (this.isPinched) {
236234
this.pinchEventDetail.position.copy(indexTipPosition).lerp(thumbTipPosition, PINCH_POSITION_INTERPOLATION);
237-
this.pinchEventDetail.position.y += 1.5;
238235
this.el.emit('pinchmoved', this.pinchEventDetail);
239236
}
240-
241-
indexTipPosition.y += 1.5;
242237
};
243238
})(),
244239

@@ -314,7 +309,7 @@ module.exports.Component = registerComponent('hand-tracking-controls', {
314309
if (!this.skinnedMesh) { return; }
315310
this.bones = skinnedMesh.skeleton.bones;
316311
this.el.removeObject3D('mesh');
317-
mesh.position.set(0, 1.5, 0);
312+
mesh.position.set(0, 0, 0);
318313
mesh.rotation.set(0, 0, 0);
319314
skinnedMesh.frustumCulled = false;
320315
skinnedMesh.material = new THREE.MeshStandardMaterial({skinning: true, color: this.data.modelColor});

‎tests/components/hand-tracking-controls.test.js‎

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ suite('tracked-controls-webxr', function () {
66
var el;
77
var system;
88
var standingMatrix = new THREE.Matrix4();
9-
var index = {transform: {position: {x: 0, y: 0, z: 0}}};
10-
var thumb = {transform: {position: {x: 0, y: 0, z: 0}}};
9+
var indexMatrix = new THREE.Matrix4();
10+
var thumbMatrix = new THREE.Matrix4();
11+
var THUMB_TIP_INDEX = 4;
12+
var INDEX_TIP_INDEX = 9;
1113
var indexPosition = new THREE.Vector3();
1214
var thumbPosition = new THREE.Vector3();
1315
var thumbObj = {};
@@ -18,15 +20,15 @@ suite('tracked-controls-webxr', function () {
1820
el = entityFactory();
1921
setTimeout(() => {
2022
el.sceneEl.addEventListener('loaded', function () {
21-
window.XRHand = {
22-
INDEX_PHALANX_TIP: 0,
23-
THUMB_PHALANX_TIP: 1
24-
};
2523
el.sceneEl.hasWebXR = true;
2624
el.sceneEl.frame = {
27-
getJointPose: function (joint, fingerPose) {
28-
var transform = joint === thumbObj ? thumb : index;
29-
return transform;
25+
fillPoses: function (joints, referenceSpace, array) {
26+
thumbMatrix.toArray(array, 16 * THUMB_TIP_INDEX);
27+
indexMatrix.toArray(array, 16 * INDEX_TIP_INDEX);
28+
return true;
29+
},
30+
fillJointRadii: function () {
31+
return true;
3032
}
3133
};
3234
system = el.sceneEl.systems['tracked-controls-webxr'];
@@ -37,11 +39,18 @@ suite('tracked-controls-webxr', function () {
3739
get: function (joint) {
3840
var jointObject = joint === 'thumb-tip' ? thumbObj : indexObj;
3941
return jointObject;
42+
},
43+
values: function () {
44+
return [
45+
{ jointName: 'thumb-tip' },
46+
{ jointName: 'index-finger-tip' }
47+
];
4048
}
4149
}
4250
};
4351
system.controllers = [controller];
4452
el.setAttribute('hand-tracking-controls', {hand: 'left'});
53+
el.components['hand-tracking-controls'].referenceSpace = {};
4554
done();
4655
});
4756
});
@@ -60,13 +69,12 @@ suite('tracked-controls-webxr', function () {
6069
test('pinchstarted', function () {
6170
const emitSpy = sinon.spy(el, 'emit');
6271
el.setAttribute('hand-tracking-controls', {hand: 'left'});
72+
el.components['hand-tracking-controls'].tick();
6373
el.components['hand-tracking-controls'].checkIfControllerPresent();
6474
el.components['hand-tracking-controls'].detectPinch();
6575
assert.equal(emitSpy.getCalls()[0].args[0], 'pinchstarted');
66-
indexPosition.copy(index.transform.position);
67-
indexPosition.y += 1.5;
68-
thumbPosition.copy(thumb.transform.position);
69-
thumbPosition.y += 1.5;
76+
indexPosition.setFromMatrixPosition(indexMatrix);
77+
thumbPosition.setFromMatrixPosition(thumbMatrix);
7078
const indexThumbDistance = indexPosition.distanceTo(thumbPosition);
7179
assert.isAtMost(emitSpy.getCalls()[0].args[1].position.distanceTo(indexPosition), indexThumbDistance);
7280
assert.isAtMost(emitSpy.getCalls()[0].args[1].position.distanceTo(thumbPosition), indexThumbDistance);
@@ -77,14 +85,12 @@ suite('tracked-controls-webxr', function () {
7785
el.setAttribute('hand-tracking-controls', {hand: 'left'});
7886
el.components['hand-tracking-controls'].checkIfControllerPresent();
7987
el.components['hand-tracking-controls'].isPinched = true;
80-
thumb.transform.position.z = 10;
81-
thumbPosition.copy(thumb.transform.position);
88+
thumbMatrix.setPosition(0, 0, 10);
89+
el.components['hand-tracking-controls'].tick();
8290
el.components['hand-tracking-controls'].detectPinch();
8391
assert.equal(emitSpy.getCalls()[0].args[0], 'pinchended');
84-
indexPosition.copy(index.transform.position);
85-
indexPosition.y += 1.5;
86-
thumbPosition.copy(thumb.transform.position);
87-
thumbPosition.y += 1.5;
92+
indexPosition.setFromMatrixPosition(indexMatrix);
93+
thumbPosition.setFromMatrixPosition(thumbMatrix);
8894
const indexThumbDistance = indexPosition.distanceTo(thumbPosition);
8995
assert.isAtMost(emitSpy.getCalls()[0].args[1].position.distanceTo(indexPosition), indexThumbDistance);
9096
assert.isAtMost(emitSpy.getCalls()[0].args[1].position.distanceTo(thumbPosition), indexThumbDistance);

0 commit comments

Comments
 (0)