Skip to content

Commit

Permalink
POC: Reparent grabbed entity onto wrist object upon grab (#5565)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrxz authored Nov 16, 2024
1 parent 746033d commit 4a415ba
Showing 1 changed file with 16 additions and 99 deletions.
115 changes: 16 additions & 99 deletions src/components/hand-tracking-grab-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ registerComponent('hand-tracking-grab-controls', {
el.setAttribute('obb-collider', {trackedObject3D: trackedObject3DVariable, size: 0.04});

this.auxMatrix = new THREE.Matrix4();
this.auxQuaternion = new THREE.Quaternion();
this.auxQuaternion2 = new THREE.Quaternion();
this.auxVector = new THREE.Vector3();
this.auxVector2 = new THREE.Vector3();

this.grabbingObjectPosition = new THREE.Vector3();
this.grabbedObjectPosition = new THREE.Vector3();
this.grabbedObjectPositionDelta = new THREE.Vector3();
this.grabDeltaPosition = new THREE.Vector3();
this.grabInitialRotation = new THREE.Quaternion();

this.onCollisionStarted = this.onCollisionStarted.bind(this);
this.el.addEventListener('obbcollisionstarted', this.onCollisionStarted);
Expand All @@ -46,9 +36,6 @@ registerComponent('hand-tracking-grab-controls', {

this.onPinchEnded = this.onPinchEnded.bind(this);
this.el.addEventListener('pinchended', this.onPinchEnded);

this.onPinchMoved = this.onPinchMoved.bind(this);
this.el.addEventListener('pinchmoved', this.onPinchMoved);
},

transferEntityOwnership: function () {
Expand Down Expand Up @@ -86,8 +73,6 @@ registerComponent('hand-tracking-grab-controls', {

onPinchStarted: function (evt) {
if (!this.collidedEl) { return; }
this.pinchPosition = evt.detail.position;
this.wristRotation = evt.detail.wristRotation;
this.grabbedEl = this.collidedEl;
this.transferEntityOwnership();
this.grab();
Expand All @@ -97,104 +82,36 @@ registerComponent('hand-tracking-grab-controls', {
this.releaseGrabbedEntity();
},

onPinchMoved: function (evt) {
this.wristRotation = evt.detail.wristRotation;
},

releaseGrabbedEntity: function () {
var grabbedEl = this.grabbedEl;
if (!grabbedEl) { return; }

grabbedEl.object3D.updateMatrixWorld = this.originalUpdateMatrixWorld;
grabbedEl.object3D.matrixAutoUpdate = true;
grabbedEl.object3D.matrixWorldAutoUpdate = true;
var child = grabbedEl.object3D;
var parent = child.parent;
var newParent = this.originalParent;

grabbedEl.object3D.matrixWorld.decompose(this.auxVector, this.auxQuaternion, this.auxVector2);
grabbedEl.object3D.position.copy(this.auxVector);
grabbedEl.object3D.quaternion.copy(this.auxQuaternion);
child.applyMatrix4(parent.matrixWorld);
child.applyMatrix4(this.auxMatrix.copy(newParent.matrixWorld).invert());
parent.remove(child);
newParent.add(child);

this.el.emit('grabended', {grabbedEl: grabbedEl});
this.grabbedEl = undefined;
this.originalParent = undefined;
},

grab: function () {
var grabbedEl = this.grabbedEl;
var grabbedObjectWorldPosition;

grabbedObjectWorldPosition = grabbedEl.object3D.getWorldPosition(this.grabbedObjectPosition);

this.grabDeltaPosition.copy(grabbedObjectWorldPosition).sub(this.pinchPosition);
this.grabInitialRotation.copy(this.auxQuaternion.copy(this.wristRotation).invert());

this.originalUpdateMatrixWorld = grabbedEl.object3D.updateMatrixWorld;
grabbedEl.object3D.updateMatrixWorld = function () { /* no op */ };
grabbedEl.object3D.updateMatrixWorldChildren = function (force) {
var children = this.children;
var child = grabbedEl.object3D;
var parent = child.parent;
this.originalParent = parent;
var newParent = this.el.components['hand-tracking-controls'].wristObject3D;

for (var i = 0, l = children.length; i < l; i++) {
var child = children[i];

if (child.matrixWorldAutoUpdate === true || force === true) {
child.updateMatrixWorld(true);
}
}
};
grabbedEl.object3D.matrixAutoUpdate = false;
grabbedEl.object3D.matrixWorldAutoUpdate = false;
child.applyMatrix4(parent.matrixWorld);
child.applyMatrix4(this.auxMatrix.copy(newParent.matrixWorld).invert());
parent.remove(child);
newParent.add(child);

this.el.emit('grabstarted', {grabbedEl: grabbedEl});
},

tock: function () {
var auxMatrix = this.auxMatrix;
var auxQuaternion = this.auxQuaternion;
var auxQuaternion2 = this.auxQuaternion2;

var grabbedObject3D;
var grabbedEl = this.grabbedEl;

if (!grabbedEl) { return; }

// We have to compose 4 transformations.
// Both grabbing and grabbed entities position and rotation.

// 1. Move grabbed entity to the pinch position (middle point between index and thumb)
// 2. Apply the rotation delta (subtract initial rotation) of the grabbing entity position (wrist).
// 3. Translate grabbed entity to the original position: distance between grabbed and grabbing entities at collision time.
// 4. Apply grabbed entity rotation.
// 5. Preserve original scale.

// Store grabbed entity local rotation.
grabbedObject3D = grabbedEl.object3D;
grabbedObject3D.getWorldQuaternion(auxQuaternion2);

// Reset grabbed entity matrix.
grabbedObject3D.matrixWorld.identity();

// 1.
auxMatrix.identity();
auxMatrix.makeTranslation(this.pinchPosition);
grabbedObject3D.matrixWorld.multiply(auxMatrix);

// 2.
auxMatrix.identity();
auxMatrix.makeRotationFromQuaternion(auxQuaternion.copy(this.wristRotation).multiply(this.grabInitialRotation));
grabbedObject3D.matrixWorld.multiply(auxMatrix);

// 3.
auxMatrix.identity();
auxMatrix.makeTranslation(this.grabDeltaPosition);
grabbedObject3D.matrixWorld.multiply(auxMatrix);

// 4.
auxMatrix.identity();
auxMatrix.makeRotationFromQuaternion(auxQuaternion2);
grabbedObject3D.matrixWorld.multiply(auxMatrix);

// 5.
auxMatrix.makeScale(grabbedEl.object3D.scale.x, grabbedEl.object3D.scale.y, grabbedEl.object3D.scale.z);
grabbedObject3D.matrixWorld.multiply(auxMatrix);

grabbedObject3D.updateMatrixWorldChildren();
}
});

0 comments on commit 4a415ba

Please sign in to comment.