Start · Sprachen · JavaScript · Referenz · XRJointSpace.jointName

XRJointSpace.jointName

Eigenschaft

Schreibgeschützte Eigenschaft, die den Namen des Handgelenks (z. B. <code>"wrist"</code> oder <code>"index-finger-tip"</code>) liefert, das dieser <code>XRJointSpace</code> verfolgt.

seit JavaScript WebXR Hand Input Module Level 1 – experimentell (C Kategorie: webapi

Signatur

XRJointSpace.jointName

Beschreibung

Die Eigenschaft jointName gehört zum Interface XRJointSpace aus dem WebXR Hand Input Module. Jeder XRJointSpace steht für genau eines der 25 Gelenke einer verfolgten Hand. jointName gibt an, um welches Gelenk es sich handelt. Der Wert ist ein String aus der Aufzählung XRHandJoint.

Mögliche Werte sind "wrist" sowie für den Daumen "thumb-metacarpal", "thumb-phalanx-proximal", "thumb-phalanx-distal" und "thumb-tip". Für jeden weiteren Finger (index-finger, middle-finger, ring-finger, pinky-finger) gibt es jeweils die Endungen -metacarpal, -phalanx-proximal, -phalanx-intermediate, -phalanx-distal und -tip.

Nützlich ist die Eigenschaft vor allem, wenn du über alle Gelenke eines XRHand-Objekts iterierst und je nach Gelenk verschieden reagieren willst. Beispiele: Nur die Fingerspitzen als Kugeln darstellen, Gesten wie ein „Pinch“ (Daumen- und Zeigefingerspitze berühren sich) erkennen oder Gelenke gezielt einem Knochen in einem 3D-Handmodell zuordnen.

Der Name wird beim Erzeugen des Space festgelegt und ändert sich danach nicht. Die eigentliche Position und Ausrichtung des Gelenks erhältst du nicht über jointName. Dafür brauchst du in jedem Frame XRFrame.getJointPose() oder XRFrame.fillPoses().

Rückgabewert

Typ
string (XRHandJoint)
Beschreibung
Der Name des verfolgten Gelenks als Wert der Aufzählung XRHandJoint, z. B. "wrist", "thumb-tip" oder "pinky-finger-phalanx-distal".

Beispiele

Alle Gelenknamen einer Hand ausgeben

// Voraussetzung: Die Session wurde mit optionalFeatures: ['hand-tracking'] angefordert
const session = await navigator.xr.requestSession('immersive-vr', {
  optionalFeatures: ['hand-tracking']
});

session.addEventListener('inputsourceschange', (event) => {
  for (const source of event.added) {
    if (!source.hand) continue; // kein Hand-Tracking für diese Eingabequelle
    // XRHand verhält sich wie eine Map: Gelenkname -> XRJointSpace
    for (const jointSpace of source.hand.values()) {
      console.log(source.handedness, jointSpace.jointName);
    }
  }
});
left wrist left thumb-metacarpal left thumb-phalanx-proximal … left pinky-finger-tip

Nur Fingerspitzen pro Frame darstellen

const onXRFrame = (time, frame) => {
  const session = frame.session;
  for (const source of session.inputSources) {
    if (!source.hand) continue;
    for (const jointSpace of source.hand.values()) {
      // Über jointName nur die Spitzen herausfiltern
      if (!jointSpace.jointName.endsWith('-tip')) continue;
      const pose = frame.getJointPose(jointSpace, refSpace);
      if (pose) {
        const { x, y, z } = pose.transform.position;
        drawSphere(jointSpace.jointName, x, y, z, pose.radius);
      }
    }
  }
  session.requestAnimationFrame(onXRFrame);
};

const drawSphere = (name, x, y, z, radius) => {
  // Platzhalter für den eigenen Renderer
  console.log(`${name}: (${x.toFixed(3)}, ${y.toFixed(3)}, ${z.toFixed(3)}) r=${radius}`);
};
thumb-tip: (0.112, 1.204, -0.301) r=0.008 index-finger-tip: (0.087, 1.231, -0.325) r=0.007 …

Pinch-Geste erkennen

const PINCH_DISTANCE = 0.015; // 1,5 cm

const isPinching = (frame, hand, refSpace) => {
  // Direkter Zugriff per Gelenkname über XRHand.get()
  const thumb = hand.get('thumb-tip');
  const index = hand.get('index-finger-tip');
  console.assert(thumb.jointName === 'thumb-tip');

  const thumbPose = frame.getJointPose(thumb, refSpace);
  const indexPose = frame.getJointPose(index, refSpace);
  if (!thumbPose || !indexPose) return false;

  const a = thumbPose.transform.position;
  const b = indexPose.transform.position;
  const distance = Math.hypot(a.x - b.x, a.y - b.y, a.z - b.z);
  return distance < PINCH_DISTANCE;
};
true (wenn Daumen- und Zeigefingerspitze sich berühren)

// Wichtig · Fallstricke

  • Experimentell: Das Hand Input Module wird bisher nur von wenigen Browsern unterstützt, etwa dem Meta Quest Browser, Chrome mit WebXR-Flag oder OpenXR-Runtime und Safari auf visionOS. Desktop-Firefox und die meisten mobilen Browser unterstützen es nicht. Prüfe vorher mit navigator.xr?.isSessionSupported() und source.hand, ob es verfügbar ist.
  • Die API steht nur in einem sicheren Kontext (HTTPS) zur Verfügung. Außerdem muss die Session das Feature 'hand-tracking' angefordert haben, sonst ist inputSource.hand null.
  • jointName ist schreibgeschützt. Eine Zuweisung wird still ignoriert, im Strict Mode löst sie einen TypeError aus.
  • Der Name sagt nichts darüber aus, ob das Gelenk gerade verfolgt wird. getJointPose() kann trotzdem undefined liefern, z. B. wenn die Hand verdeckt ist.
  • Die Namen sind feste Kleinbuchstaben-Strings mit Bindestrich. Tippfehler wie "index-tip" führen bei hand.get() zu undefined. Nutze am besten Konstanten.
  • Performance: Wenn du viele Gelenke pro Frame abfragst, ist XRFrame.fillPoses() effizienter als einzelne getJointPose()-Aufrufe.