Start · Sprachen · JavaScript · Referenz · XRPose

XRPose

Schnittstelle

Beschreibt Position und Orientierung eines <code>XRSpace</code> relativ zu einem anderen Referenzraum, inklusive optionaler Geschwindigkeiten und einem Hinweis, ob die Werte nur geschätzt sind.

seit JavaScript WebXR Device API – Chromium-Browser (Chrome/Edge 7 Kategorie: webapi

Signatur

interface XRPose

Beschreibung

XRPose ist ein Interface der WebXR Device API und steht für eine Pose, also Position plus Orientierung eines Objekts im 3D-Raum. Eine Pose gilt immer nur relativ zu einem Basis-Raum (XRSpace bzw. XRReferenceSpace). Ohne diesen Basis-Raum haben die Werte keine Bedeutung.

Einen XRPose erzeugt man nie selbst. Man bekommt ihn innerhalb eines Animations-Callbacks über XRFrame.getPose(space, baseSpace), etwa für einen Controller (inputSource.gripSpace oder targetRaySpace). Die abgeleitete Klasse XRViewerPose liefert XRFrame.getViewerPose(referenceSpace). Sie beschreibt die Pose des Betrachters, also des Headsets, und enthält zusätzlich das Array views für das Rendern pro Auge.

Wichtige Eigenschaften (alle schreibgeschützt):

  • transform (XRRigidTransform): Position (position, DOMPointReadOnly), Orientierung als Quaternion (orientation) und eine fertige 4×4-Matrix (matrix, Float32Array, spaltenweise). Die Matrix lässt sich direkt an WebGL bzw. three.js übergeben.
  • emulatedPosition (boolean): true, wenn die Position nicht gemessen, sondern geschätzt ist. Das ist z. B. bei reinem 3DoF-Tracking oder nach Verlust des Trackings der Fall.
  • linearVelocity (DOMPointReadOnly | null): Geschwindigkeit in Metern pro Sekunde, sofern das Gerät sie liefert.
  • angularVelocity (DOMPointReadOnly | null): Winkelgeschwindigkeit in Radiant pro Sekunde, sofern verfügbar.

Typische Einsätze sind: Controller-Modelle an die richtige Stelle setzen, Zeigestrahlen (Ray-Casting) berechnen, Objekte werfen (mit linearVelocity) und die Kamera eines XR-Renderers aktualisieren.

Rückgabewert

Typ
XRPose
Beschreibung
Wird von XRFrame.getPose() geliefert. Ist null, wenn sich die Pose gerade nicht bestimmen lässt, z. B. weil das Tracking verloren ist.

Beispiele

Controller-Pose im Frame-Loop abfragen

const startXR = async () => {
  const session = await navigator.xr.requestSession('immersive-vr');
  const refSpace = await session.requestReferenceSpace('local-floor');

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

    for (const source of session.inputSources) {
      if (!source.gripSpace) continue;
      // XRPose relativ zum Boden-Referenzraum
      const pose = frame.getPose(source.gripSpace, refSpace);
      if (!pose) continue; // Tracking aktuell nicht verfügbar

      const { x, y, z } = pose.transform.position;
      console.log(`${source.handedness}: ${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)}`);
    }
  };

  session.requestAnimationFrame(onFrame);
};

document.querySelector('#enter-vr').addEventListener('click', startXR);
right: 0.21, 1.05, -0.34 left: -0.18, 1.02, -0.31

Pose-Matrix direkt in WebGL verwenden

// gl, program und refSpace wurden vorher eingerichtet
const uModel = gl.getUniformLocation(program, 'uModelMatrix');

const drawController = (frame, source, refSpace) => {
  const pose = frame.getPose(source.gripSpace, refSpace);
  if (!pose) return;

  // Float32Array mit 16 Werten, spaltenweise – passt direkt zu WebGL
  gl.uniformMatrix4fv(uModel, false, pose.transform.matrix);
  gl.drawArrays(gl.TRIANGLES, 0, 36);
};

Wurfgeschwindigkeit und geschätzte Position auswerten

const onSelectEnd = (event) => {
  const { frame, inputSource } = event;
  const pose = frame.getPose(inputSource.gripSpace, refSpace);
  if (!pose) return;

  if (pose.emulatedPosition) {
    console.warn('Position nur geschätzt – Wurf ungenau');
  }

  // linearVelocity ist optional und kann null sein
  const v = pose.linearVelocity ?? { x: 0, y: 0, z: 0 };
  ball.velocity.set(v.x, v.y, v.z);
  console.log('Wurf mit', Math.hypot(v.x, v.y, v.z).toFixed(2), 'm/s');
};

session.addEventListener('selectend', onSelectEnd);
Wurf mit 3.47 m/s

// Wichtig · Fallstricke

  • Nur im aktiven Frame gültig: XRFrame.getPose() funktioniert nur innerhalb des Callbacks von XRSession.requestAnimationFrame() oder eines Eingabe-Events wie select. Außerhalb davon wird ein InvalidStateError ausgelöst. Poses sollte man nicht über Frames hinweg speichern. Wer die Werte später braucht, kopiert sie vorher.
  • Immer auf null prüfen: Geht das Tracking verloren, liefert getPose() null statt eines XRPose.
  • linearVelocity und angularVelocity werden von vielen Geräten nicht unterstützt und sind dann null. Die Geschwindigkeit sollte man in diesem Fall selbst aus den Positionen mehrerer Frames berechnen.
  • emulatedPosition === true heißt: Die Position ist geschätzt, z. B. bei 3DoF-Geräten. Positionsgenaue Interaktionen sollten dann vorsichtig behandelt werden.
  • Kompatibilität: WebXR braucht einen sicheren Kontext (HTTPS). Unterstützt wird es in Chromium-Browsern und im Meta Quest Browser. Firefox und Safari auf dem Desktop unterstützen es nicht, Safari auf der Vision Pro nur teilweise. Deshalb vorher mit navigator.xr?.isSessionSupported() prüfen, ob WebXR verfügbar ist. Auf dem Desktop hilft der Immersive Web Emulator beim Testen.
  • Alle Werte sind in Metern und Radiant angegeben. Das Koordinatensystem ist rechtshändig: +Y zeigt nach oben, −Z nach vorn.