115 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			115 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import { GLTFLoader } from '../loaders/GLTFLoader.js'; | ||
|  | 
 | ||
|  | const DEFAULT_HAND_PROFILE_PATH = 'https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles/generic-hand/'; | ||
|  | 
 | ||
|  | class XRHandMeshModel { | ||
|  | 
 | ||
|  | 	constructor( handModel, controller, path, handedness, loader = null, onLoad = null ) { | ||
|  | 
 | ||
|  | 		this.controller = controller; | ||
|  | 		this.handModel = handModel; | ||
|  | 
 | ||
|  | 		this.bones = []; | ||
|  | 
 | ||
|  | 		if ( loader === null ) { | ||
|  | 
 | ||
|  | 			loader = new GLTFLoader(); | ||
|  | 			loader.setPath( path || DEFAULT_HAND_PROFILE_PATH ); | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		loader.load( `${handedness}.glb`, gltf => { | ||
|  | 
 | ||
|  | 			const object = gltf.scene.children[ 0 ]; | ||
|  | 			this.handModel.add( object ); | ||
|  | 
 | ||
|  | 			const mesh = object.getObjectByProperty( 'type', 'SkinnedMesh' ); | ||
|  | 			mesh.frustumCulled = false; | ||
|  | 			mesh.castShadow = true; | ||
|  | 			mesh.receiveShadow = true; | ||
|  | 
 | ||
|  | 			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', | ||
|  | 			]; | ||
|  | 
 | ||
|  | 			joints.forEach( jointName => { | ||
|  | 
 | ||
|  | 				const bone = object.getObjectByName( jointName ); | ||
|  | 
 | ||
|  | 				if ( bone !== undefined ) { | ||
|  | 
 | ||
|  | 					bone.jointName = jointName; | ||
|  | 
 | ||
|  | 				} else { | ||
|  | 
 | ||
|  | 					console.warn( `Couldn't find ${jointName} in ${handedness} hand mesh` ); | ||
|  | 
 | ||
|  | 				} | ||
|  | 
 | ||
|  | 				this.bones.push( bone ); | ||
|  | 
 | ||
|  | 			} ); | ||
|  | 
 | ||
|  | 			if ( onLoad ) onLoad( object ); | ||
|  | 
 | ||
|  | 		} ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	updateMesh() { | ||
|  | 
 | ||
|  | 		// XR Joints
 | ||
|  | 		const XRJoints = this.controller.joints; | ||
|  | 
 | ||
|  | 		for ( let i = 0; i < this.bones.length; i ++ ) { | ||
|  | 
 | ||
|  | 			const bone = this.bones[ i ]; | ||
|  | 
 | ||
|  | 			if ( bone ) { | ||
|  | 
 | ||
|  | 				const XRJoint = XRJoints[ bone.jointName ]; | ||
|  | 
 | ||
|  | 				if ( XRJoint.visible ) { | ||
|  | 
 | ||
|  | 					const position = XRJoint.position; | ||
|  | 
 | ||
|  | 					bone.position.copy( position ); | ||
|  | 					bone.quaternion.copy( XRJoint.quaternion ); | ||
|  | 					// bone.scale.setScalar( XRJoint.jointRadius || defaultRadius );
 | ||
|  | 
 | ||
|  | 				} | ||
|  | 
 | ||
|  | 			} | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | export { XRHandMeshModel }; |