1
0

Hand tracking
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
Aiden
2026-06-10 14:54:56 +10:00
parent c1fbfd3b5e
commit ba3c2785d8
6 changed files with 436 additions and 32 deletions

View File

@@ -1,41 +1,58 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { computePalmAimRay } from '../vr180player/xr/hand-aim.js';
import {
beginPalmAimSelection,
computePalmAimRay,
createPalmAimLatch,
endPalmAimSelection,
getPalmAimSelectionRay,
recordStablePalmAimRay
} from '../vr180player/xr/hand-aim.js';
const wrist = { x: 0, y: 0, z: 0 };
const middleMetacarpal = { x: 0, y: 0.1, z: 0 };
const ringMetacarpal = { x: 0.025, y: 0.1, z: 0 };
const straightAheadRay = {
direction: { x: 0, y: 0, z: -1 },
origin: { x: 0, y: 1.4, z: -0.04 }
};
const pinchedRay = {
direction: { x: 0.4, y: -0.2, z: -0.8 },
origin: { x: 0.04, y: 1.32, z: -0.03 }
};
test('computePalmAimRay points out from a right palm instead of following the index finger', () => {
test('computePalmAimRay tilts a right palm ray toward the finger-forward axis', () => {
const ray = computePalmAimRay({
handedness: 'right',
indexMetacarpal: { x: -0.035, y: 0.1, z: 0 },
middleMetacarpal,
pinkyMetacarpal: { x: 0.055, y: 0.1, z: 0 },
ringMetacarpal,
indexMetacarpal: { x: -0.045, y: 0.1, z: 0 },
middleMetacarpal: { x: -0.015, y: 0.1, z: 0 },
pinkyMetacarpal: { x: 0.045, y: 0.1, z: 0 },
ringMetacarpal: { x: 0.015, y: 0.1, z: 0 },
wrist
});
assert.ok(ray);
assert.equal(Math.round(ray.direction.x * 1000) / 1000, 0);
assert.equal(Math.round(ray.direction.y * 1000) / 1000, 0);
assert.equal(Math.round(ray.direction.z * 1000) / 1000, -1);
assert.equal(Math.round(ray.origin.z * 1000) / 1000, -0.035);
assert.equal(Math.round(ray.direction.y * 1000) / 1000, 0.643);
assert.equal(Math.round(ray.direction.z * 1000) / 1000, -0.766);
assert.equal(Math.round(ray.origin.y * 1000) / 1000, 0.084);
assert.equal(Math.round(ray.origin.z * 1000) / 1000, -0.027);
});
test('computePalmAimRay flips the palm normal for a left hand', () => {
test('computePalmAimRay flips the palm normal for a left hand while keeping forward tilt', () => {
const ray = computePalmAimRay({
handedness: 'left',
indexMetacarpal: { x: 0.035, y: 0.1, z: 0 },
middleMetacarpal,
pinkyMetacarpal: { x: -0.055, y: 0.1, z: 0 },
ringMetacarpal: { x: -0.025, y: 0.1, z: 0 },
indexMetacarpal: { x: 0.045, y: 0.1, z: 0 },
middleMetacarpal: { x: 0.015, y: 0.1, z: 0 },
pinkyMetacarpal: { x: -0.045, y: 0.1, z: 0 },
ringMetacarpal: { x: -0.015, y: 0.1, z: 0 },
wrist
});
assert.ok(ray);
assert.equal(Math.round(ray.direction.z * 1000) / 1000, -1);
assert.equal(Math.round(ray.direction.y * 1000) / 1000, 0.643);
assert.equal(Math.round(ray.direction.z * 1000) / 1000, -0.766);
});
test('computePalmAimRay returns null when palm joints cannot define a stable ray', () => {
@@ -47,3 +64,38 @@ test('computePalmAimRay returns null when palm joints cannot define a stable ray
wrist
}), null);
});
test('palm aim latch returns the latest fresh stable ray', () => {
const latch = createPalmAimLatch();
recordStablePalmAimRay(latch, straightAheadRay, 100);
assert.deepEqual(getPalmAimSelectionRay(latch, 120), straightAheadRay);
assert.equal(getPalmAimSelectionRay(latch, 500), null);
});
test('palm aim latch freezes the pre-selection ray while selecting', () => {
const latch = createPalmAimLatch();
recordStablePalmAimRay(latch, straightAheadRay, 100);
assert.deepEqual(beginPalmAimSelection(latch, 120), straightAheadRay);
recordStablePalmAimRay(latch, pinchedRay, 130);
assert.deepEqual(getPalmAimSelectionRay(latch, 140), straightAheadRay);
assert.deepEqual(getPalmAimSelectionRay(latch, 1000), straightAheadRay);
endPalmAimSelection(latch);
recordStablePalmAimRay(latch, pinchedRay, 150);
assert.deepEqual(getPalmAimSelectionRay(latch, 160), pinchedRay);
});
test('palm aim latch ignores stale rays when selection starts too late', () => {
const latch = createPalmAimLatch();
recordStablePalmAimRay(latch, straightAheadRay, 100);
assert.equal(beginPalmAimSelection(latch, 450), null);
assert.equal(getPalmAimSelectionRay(latch, 450), null);
});