Browse Source

Merge pull request #20938 from cabanier/updated-hands

Updated WebXR Hand implementation to the new API
Mr.doob 4 years ago
parent
commit
713c4269af

+ 43 - 2
examples/jsm/webxr/XRHandOculusMeshModel.js

@@ -55,11 +55,49 @@ class XRHandOculusMeshModel {
 				'b_%_pinky3', // XRHand.LITTLE_PHALANX_DISTAL,
 				'b_%_pinkynull', // XRHand.LITTLE_PHALANX_TIP
 			];
+
+			const joints = [
+				'wrist',
+				'thumb-metacarpal',
+				'thumb-phalanx-proximal',
+				'thumb-phalanx-distal',
+				'thumb-tip',
+				'index-finger-metacarpal',
+				'index-finger-phalanx-proximal',
+				'index-finger-phalanx-intermediate',
+				'index-finger-phalanx-distal',
+				'index-finger-tip',
+				'middle-finger-metacarpal',
+				'middle-finger-phalanx-proximal',
+				'middle-finger-phalanx-intermediate',
+				'middle-finger-phalanx-distal',
+				'middle-finger-tip',
+				'ring-finger-metacarpal',
+				'ring-finger-phalanx-proximal',
+				'ring-finger-phalanx-intermediate',
+				'ring-finger-phalanx-distal',
+				'ring-finger-tip',
+				'pinky-finger-metacarpal',
+				'pinky-finger-phalanx-proximal',
+				'pinky-finger-phalanx-intermediate',
+				'pinky-finger-phalanx-distal',
+				'pinky-finger-tip',
+			];
+
+			let i = 0;
+
 			bonesMapping.forEach( boneName => {
 
 				if ( boneName ) {
 
 					const bone = object.getObjectByName( boneName.replace( /%/g, handedness === 'right' ? 'r' : 'l' ) );
+
+					if ( bone !== undefined) {
+
+						bone.jointName = joints [ i ];
+
+					}
+
 					this.bones.push( bone );
 
 				} else {
@@ -68,6 +106,8 @@ class XRHandOculusMeshModel {
 
 				}
 
+				i ++;
+
 			} );
 
 		} );
@@ -81,9 +121,10 @@ class XRHandOculusMeshModel {
 		for ( let i = 0; i < this.bones.length; i ++ ) {
 
 			const bone = this.bones[ i ];
-			const XRJoint = XRJoints[ i ];
 
-			if ( XRJoint ) {
+			if ( bone ) {
+
+				const XRJoint = XRJoints[ bone.jointName ];
 
 				if ( XRJoint.visible ) {
 

+ 31 - 9
examples/jsm/webxr/XRHandPrimitiveModel.js

@@ -35,18 +35,40 @@ class XRHandPrimitiveModel {
 			const jointMaterial = new MeshStandardMaterial( { color: 0xffffff, roughness: 1, metalness: 0 } );
 			const tipMaterial = new MeshStandardMaterial( { color: 0x999999, roughness: 1, metalness: 0 } );
 
-			const tipIndexes = [
-				window.XRHand.THUMB_PHALANX_TIP,
-				window.XRHand.INDEX_PHALANX_TIP,
-				window.XRHand.MIDDLE_PHALANX_TIP,
-				window.XRHand.RING_PHALANX_TIP,
-				window.XRHand.LITTLE_PHALANX_TIP
+			const joints = [
+				'wrist',
+				'thumb-metacarpal',
+				'thumb-phalanx-proximal',
+				'thumb-phalanx-distal',
+				'thumb-tip',
+				'index-finger-metacarpal',
+				'index-finger-phalanx-proximal',
+				'index-finger-phalanx-intermediate',
+				'index-finger-phalanx-distal',
+				'index-finger-tip',
+				'middle-finger-metacarpal',
+				'middle-finger-phalanx-proximal',
+				'middle-finger-phalanx-intermediate',
+				'middle-finger-phalanx-distal',
+				'middle-finger-tip',
+				'ring-finger-metacarpal',
+				'ring-finger-phalanx-proximal',
+				'ring-finger-phalanx-intermediate',
+				'ring-finger-phalanx-distal',
+				'ring-finger-tip',
+				'pinky-finger-metacarpal',
+				'pinky-finger-phalanx-proximal',
+				'pinky-finger-phalanx-intermediate',
+				'pinky-finger-phalanx-distal',
+				'pinky-finger-tip'
 			];
-			for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
 
-				var cube = new Mesh( geometry, tipIndexes.indexOf( i ) !== - 1 ? tipMaterial : jointMaterial );
+			for ( const jointName of joints ) {
+
+				var cube = new Mesh( geometry, jointName.indexOf( 'tip' ) !== - 1 ? tipMaterial : jointMaterial );
 				cube.castShadow = true;
 				cube.receiveShadow = true;
+				cube.jointName = jointName;
 				this.handMesh.add( cube );
 
 			}
@@ -66,7 +88,7 @@ class XRHandPrimitiveModel {
 		for ( let i = 0; i < objects.length; i ++ ) {
 
 			const jointMesh = objects[ i ];
-			const XRJoint = XRJoints[ i ];
+			const XRJoint = XRJoints[ jointMesh.jointName ];
 
 			if ( XRJoint.visible ) {
 

+ 6 - 6
examples/webxr_vr_handinput_cubes.html

@@ -163,7 +163,7 @@
 
 				if ( grabbing ) {
 
-					const indexTip = controller.joints[ XRHand.INDEX_PHALANX_TIP ];
+					const indexTip = controller.joints[ 'index-finger-tip' ];
 					const sphere = collideObject( indexTip );
 
 					if ( sphere ) {
@@ -175,7 +175,7 @@
 							scaling.active = true;
 							scaling.object = sphere;
 							scaling.initialScale = sphere.scale.x;
-							scaling.initialDistance = indexTip.position.distanceTo( hand2.joints[ XRHand.INDEX_PHALANX_TIP ].position );
+							scaling.initialDistance = indexTip.position.distanceTo( hand2.joints[ 'index-finger-tip' ].position );
 							return;
 
 						}
@@ -193,7 +193,7 @@
 				const spawn = new THREE.Mesh( geometry, material );
 				spawn.geometry.computeBoundingSphere();
 
-				const indexTip = controller.joints[ XRHand.INDEX_PHALANX_TIP ];
+				const indexTip = controller.joints[ 'index-finger-tip' ];
 				spawn.position.copy( indexTip.position );
 				spawn.quaternion.copy( indexTip.quaternion );
 
@@ -225,7 +225,7 @@
 			function onPinchStartRight( event ) {
 
 				const controller = event.target;
-				const indexTip = controller.joints[ XRHand.INDEX_PHALANX_TIP ];
+				const indexTip = controller.joints[ 'index-finger-tip' ];
 				const object = collideObject( indexTip );
 				if ( object ) {
 
@@ -269,8 +269,8 @@
 
 				if ( scaling.active ) {
 
-					const indexTip1Pos = hand1.joints[ XRHand.INDEX_PHALANX_TIP ].position;
-					const indexTip2Pos = hand2.joints[ XRHand.INDEX_PHALANX_TIP ].position;
+					const indexTip1Pos = hand1.joints[ 'index-finger-tip' ].position;
+					const indexTip2Pos = hand2.joints[ 'index-finger-tip' ].position;
 					const distance = indexTip1Pos.distanceTo( indexTip2Pos );
 					const newScale = scaling.initialScale + distance / scaling.initialDistance - 1;
 					scaling.object.scale.setScalar( newScale );

+ 34 - 37
src/renderers/webxr/WebXR.d.ts

@@ -264,47 +264,44 @@ export interface XRPlane {
 	lastChangedTime: number;
 }
 
-export interface XRJointSpace extends XRSpace {}
+export declare enum XRHandJoint {
+	'wrist',
+	'thumb-metacarpal',
+	'thumb-phalanx-proximal',
+	'thumb-phalanx-distal',
+	'thumb-tip',
+	'index-finger-metacarpal',
+	'index-finger-phalanx-proximal',
+	'index-finger-phalanx-intermediate',
+	'index-finger-phalanx-distal',
+	'index-finger-tip',
+	'middle-finger-metacarpal',
+	'middle-finger-phalanx-proximal',
+	'middle-finger-phalanx-intermediate',
+	'middle-finger-phalanx-distal',
+	'middle-finger-tip',
+	'ring-finger-metacarpal',
+	'ring-finger-phalanx-proximal',
+	'ring-finger-phalanx-intermediate',
+	'ring-finger-phalanx-distal',
+	'ring-finger-tip',
+	'pinky-finger-metacarpal',
+	'pinky-finger-phalanx-proximal',
+	'pinky-finger-phalanx-intermediate',
+	'pinky-finger-phalanx-distal',
+	'pinky-finger-tip'
+}
+
+export interface XRJointSpace extends XRSpace {
+	readonly jointName: XRHandJoint;
+}
 
 export interface XRJointPose extends XRPose {
-	radius: number | undefined;
+	readonly radius: number | undefined;
 }
 
-export declare class XRHand extends Array<XRJointSpace> {
-
-	readonly length: number;
-
-	static readonly WRIST = 0;
-
-	static readonly THUMB_METACARPAL = 1;
-	static readonly THUMB_PHALANX_PROXIMAL = 2;
-	static readonly THUMB_PHALANX_DISTAL = 3;
-	static readonly THUMB_PHALANX_TIP = 4;
-
-	static readonly INDEX_METACARPAL = 5;
-	static readonly INDEX_PHALANX_PROXIMAL = 6;
-	static readonly INDEX_PHALANX_INTERMEDIATE = 7;
-	static readonly INDEX_PHALANX_DISTAL = 8;
-	static readonly INDEX_PHALANX_TIP = 9;
-
-	static readonly MIDDLE_METACARPAL = 10;
-	static readonly MIDDLE_PHALANX_PROXIMAL = 11;
-	static readonly MIDDLE_PHALANX_INTERMEDIATE = 12;
-	static readonly MIDDLE_PHALANX_DISTAL = 13;
-	static readonly MIDDLE_PHALANX_TIP = 14;
-
-	static readonly RING_METACARPAL = 15;
-	static readonly RING_PHALANX_PROXIMAL = 16;
-	static readonly RING_PHALANX_INTERMEDIATE = 17;
-	static readonly RING_PHALANX_DISTAL = 18;
-	static readonly RING_PHALANX_TIP = 19;
-
-	static readonly LITTLE_METACARPAL = 20;
-	static readonly LITTLE_PHALANX_PROXIMAL = 21;
-	static readonly LITTLE_PHALANX_INTERMEDIATE = 22;
-	static readonly LITTLE_PHALANX_DISTAL = 23;
-	static readonly LITTLE_PHALANX_TIP = 24;
-
+export interface XRHand extends Map<XRHandJoint, XRJointSpace> {
+	readonly size: number;
 }
 
 declare type Constructor<T = object> = {

+ 44 - 51
src/renderers/webxr/WebXRController.js

@@ -20,25 +20,9 @@ Object.assign( WebXRController.prototype, {
 			this._hand.matrixAutoUpdate = false;
 			this._hand.visible = false;
 
-			this._hand.joints = [];
+			this._hand.joints = {};
 			this._hand.inputState = { pinching: false };
 
-			if ( window.XRHand ) {
-
-				for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
-
-					// The transform of this joint will be updated with the joint pose on each frame
-					const joint = new Group();
-					joint.matrixAutoUpdate = false;
-					joint.visible = false;
-					this._hand.joints.push( joint );
-					// ??
-					this._hand.add( joint );
-
-				}
-
-			}
-
 		}
 
 		return this._hand;
@@ -139,55 +123,64 @@ Object.assign( WebXRController.prototype, {
 
 				handPose = true;
 
-				for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
+				for ( const inputjoint of inputSource.hand.values() ) {
 
-					if ( inputSource.hand[ i ] ) {
+					// Update the joints groups with the XRJoint poses
+					const jointPose = frame.getJointPose( inputjoint, referenceSpace );
 
-						// Update the joints groups with the XRJoint poses
-						const jointPose = frame.getJointPose( inputSource.hand[ i ], referenceSpace );
-						const joint = hand.joints[ i ];
+					if ( hand.joints[ inputjoint.jointName ] === undefined ) {
 
-						if ( jointPose !== null ) {
+						// The transform of this joint will be updated with the joint pose on each frame
+						const joint = new Group();
+						joint.matrixAutoUpdate = false;
+						joint.visible = false;
+						hand.joints[ inputjoint.jointName ] = joint;
+						// ??
+						hand.add( joint );
 
-							joint.matrix.fromArray( jointPose.transform.matrix );
-							joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
-							joint.jointRadius = jointPose.radius;
+					}
+
+					const joint = hand.joints[ inputjoint.jointName ];
+
+					if ( jointPose !== null ) {
 
-						}
+						joint.matrix.fromArray( jointPose.transform.matrix );
+						joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
+						joint.jointRadius = jointPose.radius;
 
-						joint.visible = jointPose !== null;
+					}
 
-						// Custom events
+					joint.visible = jointPose !== null;
 
-						// Check pinch
-						const indexTip = hand.joints[ window.XRHand.INDEX_PHALANX_TIP ];
-						const thumbTip = hand.joints[ window.XRHand.THUMB_PHALANX_TIP ];
-						const distance = indexTip.position.distanceTo( thumbTip.position );
+				}
 
-						const distanceToPinch = 0.02;
-						const threshold = 0.005;
+				// Custom events
 
-						if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
+				// Check pinchz
+				const indexTip = hand.joints[ 'index-finger-tip' ];
+				const thumbTip = hand.joints[ 'thumb-tip' ];
+				const distance = indexTip.position.distanceTo( thumbTip.position );
 
-							hand.inputState.pinching = false;
-							this.dispatchEvent( {
-								type: 'pinchend',
-								handedness: inputSource.handedness,
-								target: this
-							} );
+				const distanceToPinch = 0.02;
+				const threshold = 0.005;
 
-						} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
+				if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
 
-							hand.inputState.pinching = true;
-							this.dispatchEvent( {
-								type: 'pinchstart',
-								handedness: inputSource.handedness,
-								target: this
-							} );
+					hand.inputState.pinching = false;
+					this.dispatchEvent( {
+						type: 'pinchend',
+						handedness: inputSource.handedness,
+						target: this
+					} );
 
-						}
+				} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
 
-					}
+					hand.inputState.pinching = true;
+					this.dispatchEvent( {
+						type: 'pinchstart',
+						handedness: inputSource.handedness,
+						target: this
+					} );
 
 				}