Start · Sprachen · JavaScript · Referenz · XRFrame.fillPoses()

XRFrame.fillPoses()

Methode

Schreibt die 4×4-Posenmatrizen mehrerer <code>XRSpace</code>-Objekte relativ zu einem Basisraum in ein <code>Float32Array</code> und liefert <code>true</code>, wenn alle Posen ermittelt werden konnten.

seit JavaScript WebXR Hand Input Module Level 1 – Chromium-basiert Kategorie: webapi

Signatur

XRFrame.prototype.fillPoses(spaces, baseSpace, transforms)

Beschreibung

Die Methode fillPoses() der Schnittstelle XRFrame ermittelt in einem einzigen Aufruf die Posen vieler Räume auf einmal. Für jeden Eintrag in spaces wird eine 4×4-Transformationsmatrix (16 Gleitkommazahlen, spaltenweise wie bei WebGL) relativ zu baseSpace berechnet und nacheinander in das übergebene Float32Array geschrieben – der erste Raum belegt die Indizes 0–15, der zweite 16–31 usw.

Gedacht ist die Methode vor allem für das Hand-Tracking: Eine XRHand besteht aus 25 XRJointSpace-Objekten. Statt 25-mal frame.getJointPose() aufzurufen und dabei jedes Mal neue XRPose- und XRRigidTransform-Objekte zu erzeugen, füllt fillPoses() einen einmal angelegten Puffer. Das spart Speicherbelegung und entlastet den Garbage Collector – wichtig bei 72–120 Bildern pro Sekunde.

Die Methode darf nur innerhalb des Callbacks von XRSession.requestAnimationFrame() auf dem gerade aktiven Frame aufgerufen werden. Der Rückgabewert zeigt an, ob alle Posen gültig sind: Kann auch nur eine Pose nicht ermittelt werden (z. B. weil ein Finger verdeckt ist oder das Tracking verloren ging), ist das Ergebnis false und die 16 Werte dieses Raums werden mit NaN belegt.

Passend dazu gibt es XRFrame.fillJointRadii(), das die Radien der Gelenke in ein weiteres Float32Array schreibt – zusammen genügen beide Aufrufe, um eine Hand vollständig zu zeichnen.

Parameter

Name Typ Default Beschreibung
$spaces Pflicht Iterable<XRSpace> | XRSpace[] Folge der Räume, deren Posen ermittelt werden sollen – typischerweise die Gelenke einer XRHand (z. B. hand.values() bzw. [...hand.values()]).
$baseSpace Pflicht XRSpace Bezugsraum, relativ zu dem die Posen berechnet werden, meist der mit requestReferenceSpace() angeforderte XRReferenceSpace.
$transforms Pflicht Float32Array Zielpuffer. Muss mindestens spaces.length * 16 Elemente lang sein, sonst wird ein TypeError geworfen. Wird direkt überschrieben.

Beispiele

Gelenkposen beider Hände pro Frame auslesen

const JOINTS = 25;
// Puffer einmalig anlegen – nicht in jedem Frame neu!
const poseBuffers = new Map();

const onXRFrame = (time, frame) => {
  const session = frame.session;
  session.requestAnimationFrame(onXRFrame);

  for (const source of session.inputSources) {
    if (!source.hand) continue;

    let buffer = poseBuffers.get(source.handedness);
    if (!buffer) {
      buffer = new Float32Array(JOINTS * 16);
      poseBuffers.set(source.handedness, buffer);
    }

    const ok = frame.fillPoses(source.hand.values(), refSpace, buffer);
    if (ok) {
      // Position der Zeigefingerspitze: Translation steht in Index 12–14
      const joints = [...source.hand.keys()];
      const i = joints.indexOf('index-finger-tip') * 16;
      console.log(source.handedness, buffer[i + 12].toFixed(3), buffer[i + 13].toFixed(3), buffer[i + 14].toFixed(3));
    }
  }
};

let refSpace;
const start = async () => {
  const session = await navigator.xr.requestSession('immersive-vr', {
    optionalFeatures: ['hand-tracking']
  });
  refSpace = await session.requestReferenceSpace('local-floor');
  session.requestAnimationFrame(onXRFrame);
};

document.querySelector('#vr-button').addEventListener('click', start);
right 0.142 1.203 -0.318 left -0.155 1.187 -0.302

Hand mit Instanced Rendering zeichnen (Posen + Radien)

const JOINTS = 25;
const matrices = new Float32Array(JOINTS * 16);
const radii = new Float32Array(JOINTS);

const drawHand = (frame, hand, refSpace, gl, instanceBuffer) => {
  const posesOk = frame.fillPoses(hand.values(), refSpace, matrices);
  const radiiOk = frame.fillJointRadii(hand.values(), radii);

  if (!posesOk || !radiiOk) {
    return false; // Hand teilweise verdeckt – Frame auslassen
  }

  // Matrizen direkt als Instanzdaten an die GPU übergeben
  gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
  gl.bufferSubData(gl.ARRAY_BUFFER, 0, matrices);
  gl.drawArraysInstanced(gl.TRIANGLES, 0, 36, JOINTS);
  return true;
};

Fehlende Posen einzeln erkennen

const countValidPoses = (frame, spaces, baseSpace) => {
  const list = [...spaces];
  const buffer = new Float32Array(list.length * 16);
  const allValid = frame.fillPoses(list, baseSpace, buffer);

  // Bei false sind ungültige Matrizen mit NaN gefüllt
  let valid = 0;
  for (let i = 0; i < list.length; i++) {
    if (!Number.isNaN(buffer[i * 16])) valid++;
  }
  return { allValid, valid, total: list.length };
};

// innerhalb eines XR-Frame-Callbacks:
// console.log(countValidPoses(frame, hand.values(), refSpace));
{ allValid: false, valid: 21, total: 25 }