three
Version:
JavaScript 3D library
148 lines (116 loc) • 3.49 kB
JavaScript
import {
DynamicDrawUsage,
SphereGeometry,
BoxGeometry,
MeshStandardMaterial,
InstancedMesh,
Matrix4,
Vector3
} from 'three';
const _matrix = new Matrix4();
const _vector = new Vector3();
/**
* Represents one of the hand model types {@link XRHandModelFactory} might produce
* depending on the selected profile. `XRHandPrimitiveModel` represents a hand
* with sphere or box primitives according to the selected `primitive` option.
*
* @three_import import { XRHandPrimitiveModel } from 'three/addons/webxr/XRHandPrimitiveModel.js';
*/
class XRHandPrimitiveModel {
/**
* Constructs a new XR hand primitive 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 {XRHandPrimitiveModel~Options} options - The model options.
*/
constructor( handModel, controller, path, handedness, options ) {
/**
* The WebXR controller.
*
* @type {Group}
*/
this.controller = controller;
/**
* The hand model.
*
* @type {XRHandModel}
*/
this.handModel = handModel;
/**
* The model's environment map.
*
* @type {?Texture}
* @default null
*/
this.envMap = null;
let geometry;
if ( ! options || ! options.primitive || options.primitive === 'sphere' ) {
geometry = new SphereGeometry( 1, 10, 10 );
} else if ( options.primitive === 'box' ) {
geometry = new BoxGeometry( 1, 1, 1 );
}
const material = new MeshStandardMaterial();
this.handMesh = new InstancedMesh( geometry, material, 30 );
this.handMesh.frustumCulled = false;
this.handMesh.instanceMatrix.setUsage( DynamicDrawUsage ); // will be updated every frame
this.handMesh.castShadow = true;
this.handMesh.receiveShadow = true;
this.handModel.add( this.handMesh );
this.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'
];
}
/**
* Updates the mesh based on the tracked XR joints data.
*/
updateMesh() {
const defaultRadius = 0.008;
const joints = this.controller.joints;
let count = 0;
for ( let i = 0; i < this.joints.length; i ++ ) {
const joint = joints[ this.joints[ i ] ];
if ( joint.visible ) {
_vector.setScalar( joint.jointRadius || defaultRadius );
_matrix.compose( joint.position, joint.quaternion, _vector );
this.handMesh.setMatrixAt( i, _matrix );
count ++;
}
}
this.handMesh.count = count;
this.handMesh.instanceMatrix.needsUpdate = true;
}
}
/**
* Constructor options of `XRHandPrimitiveModel`.
*
* @typedef {Object} XRHandPrimitiveModel~Options
* @property {('box'|'sphere')} [primitive] - The primitive type.
**/
export { XRHandPrimitiveModel };