123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- 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/';
- /**
- * Represents one of the hand model types {@link XRHandModelFactory} might produce
- * depending on the selected profile. `XRHandMeshModel` represents a hand with a
- * custom asset.
- *
- * @three_import import { XRHandMeshModel } from 'three/addons/webxr/XRHandMeshModel.js';
- */
- class XRHandMeshModel {
- /**
- * Constructs a new XR hand mesh model.
- *
- * @param {XRHandModel} handModel - The hand model.
- * @param {Group} controller - The WebXR controller.
- * @param {?string} path - The model path.
- * @param {XRHandedness} handedness - The handedness of the XR input source.
- * @param {?Loader} [loader=null] - The loader. If not provided, an instance of `GLTFLoader` will be used to load models.
- * @param {?Function} [onLoad=null] - A callback that is executed when a controller model has been loaded.
- */
- constructor( handModel, controller, path, handedness, loader = null, onLoad = null ) {
- /**
- * The WebXR controller.
- *
- * @type {Group}
- */
- this.controller = controller;
- /**
- * The hand model.
- *
- * @type {XRHandModel}
- */
- this.handModel = handModel;
- /**
- * An array of bones representing the bones
- * of the hand skeleton.
- *
- * @type {Array<Bone>}
- */
- 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 );
- } );
- }
- /**
- * Updates the mesh based on the tracked XR joints data.
- */
- 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 };
|