UNPKG

aframe-leap-hands

Version:
160 lines (134 loc) 4.74 kB
import { HandMesh } from '../lib/leap.hand-mesh'; import { HandBody } from './helpers/hand-body'; import { Intersector } from './helpers/intersector'; import { CircularArray } from '../lib/circular-array'; var nextID = 1; /** * A-Frame component for a single Leap Motion hand. */ const Component = AFRAME.registerComponent('leap-hand', { schema: { hand: {default: '', oneOf: ['left', 'right'], required: true}, enablePhysics: {default: false}, holdDistance: {default: 0.2}, // m holdDebounce: {default: 100}, // ms holdSelector: {default: '[holdable]'}, holdSensitivity: {default: 0.95}, // [0,1] releaseSensitivity: {default: 0.75}, // [0,1] debug: {default: false} }, init: function () { this.system = this.el.sceneEl.systems.leap; this.handID = nextID++; this.hand = /** @type {Leap.Hand} */ null; this.handBody = /** @type {HandBody} */ null; this.handMesh = new HandMesh(); this.isVisible = false; this.isHolding = false; var bufferLen = Math.floor(this.data.holdDebounce / (1000 / 120)); this.grabStrength = 0; this.pinchStrength = 0; this.grabStrengthBuffer = /** @type {CircularArray<number>} */ new CircularArray(bufferLen); this.pinchStrengthBuffer = /** @type {CircularArray<number>} */ new CircularArray(bufferLen); this.intersector = new Intersector(); this.holdTarget = /** @type {AFRAME.Element} */ null; this.el.setObject3D('mesh', this.handMesh.getMesh()); this.handMesh.hide(); if (this.data.debug) { this.el.object3D.add(this.intersector.getMesh()); } }, update: function () { var data = this.data; if (data.enablePhysics && !this.handBody) { this.handBody = new HandBody(this.el, this); } else if (!data.enablePhysics && this.handBody) { this.handBody.remove(); this.handBody = null; } }, remove: function () { if (this.handMesh) { this.el.removeObject3D('mesh'); this.handMesh = null; } if (this.handBody) { this.handBody.remove(); this.handBody = null; } if (this.intersector.getMesh()) { this.el.object3D.remove(this.intersector.getMesh()); this.intersector = null; } }, tick: function () { var hand = this.getHand(); if (hand && hand.valid) { this.handMesh.scaleTo(hand); this.handMesh.formTo(hand); this.grabStrengthBuffer.push(hand.grabStrength); this.pinchStrengthBuffer.push(hand.pinchStrength); this.grabStrength = circularArrayAvg(this.grabStrengthBuffer); this.pinchStrength = circularArrayAvg(this.pinchStrengthBuffer); var isHolding = Math.max(this.grabStrength, this.pinchStrength) > (this.isHolding ? this.data.releaseSensitivity : this.data.holdSensitivity); this.intersector.update(this.data, this.el.object3D, hand, isHolding); if ( isHolding && !this.isHolding) this.hold(hand); if (!isHolding && this.isHolding) this.release(hand); } else if (this.isHolding) { this.release(null); } if (hand && !this.isVisible) { this.handMesh.show(); this.intersector.show(); } if (!hand && this.isVisible) { this.handMesh.hide(); this.intersector.hide(); } this.isVisible = !!hand; }, getHand: function () { var data = this.data, frame = this.system.getFrame(); return frame.hands.length ? frame.hands[frame.hands[0].type === data.hand ? 0 : 1] : null; }, hold: function (hand) { var objects, results, eventDetail = this.getEventDetail(hand); this.el.emit('leap-holdstart', eventDetail); objects = [].slice.call(this.el.sceneEl.querySelectorAll(this.data.holdSelector)) .map(function (el) { return el.object3D; }); results = this.intersector.intersectObjects(objects, true); this.holdTarget = results[0] && results[0].object && results[0].object.el; if (this.holdTarget) { this.holdTarget.emit('leap-holdstart', eventDetail); } this.isHolding = true; }, release: function (hand) { var eventDetail = this.getEventDetail(hand); this.el.emit('leap-holdstop', eventDetail); if (this.holdTarget) { this.holdTarget.emit('leap-holdstop', eventDetail); this.holdTarget = null; } this.isHolding = false; }, getEventDetail: function (hand) { return { hand: hand, handID: this.handID, body: this.handBody ? this.handBody.palmBody : null }; } }); function circularArrayAvg (array) { var avg = 0; array = array.array(); for (var i = 0; i < array.length; i++) { avg += array[i]; } return avg / array.length; } export { Component };