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

XRFrame.getViewerPose()

Methode

Gibt ein <code>XRViewerPose</code> zurück, das Position und Ausrichtung des Betrachters relativ zum angegebenen Referenzraum beschreibt – oder <code>null</code>, wenn keine Pose ermittelt werden kann.

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

Signatur

XRFrame.prototype.getViewerPose(referenceSpace)

Beschreibung

getViewerPose() ist der zentrale Aufruf in jeder WebXR-Renderschleife. Innerhalb des Callbacks von XRSession.requestAnimationFrame() liefert die Methode die aktuelle Pose des Betrachters (Kopf bzw. Gerät) im übergebenen XRReferenceSpace. Das zurückgegebene XRViewerPose erbt von XRPose und enthält neben transform auch das Array views. Darin liegt ein XRView pro Auge oder Anzeige, jeweils mit eigener Projektionsmatrix und eigener Blickmatrix.

Aus diesen Views renderst du die Szene: Für jede XRView holst du über XRWebGLLayer.getViewport(view) den passenden Viewport und zeichnest die Szene mit view.projectionMatrix und view.transform.inverse.matrix (der Blickmatrix). Bei einem VR-Headset gibt es normalerweise zwei Views, bei Handheld-AR auf dem Smartphone einen.

Die Methode gibt null zurück, wenn das Tracking die Pose gerade nicht bestimmen kann, zum Beispiel beim Start, bei verdeckten Sensoren oder wenn das Tracking verloren geht. Behandle diesen Fall immer. Meist lässt du den Frame dann einfach aus oder zeichnest den letzten Zustand noch einmal. Die Eigenschaft emulatedPosition zeigt an, ob die Position nur geschätzt ist. Das ist etwa bei Geräten der Fall, die nur die Drehung erfassen (3DoF).

Parameter

Name Typ Default Beschreibung
$referenceSpace Pflicht XRReferenceSpace Der Referenzraum, in dem die Pose angegeben wird, z. B. aus session.requestReferenceSpace('local'), 'local-floor' oder 'bounded-floor'.

Rückgabewert

Typ
XRViewerPose | null
Beschreibung
Ein XRViewerPose mit transform, views, emulatedPosition sowie gegebenenfalls linearVelocity und angularVelocity. null, wenn keine Pose verfügbar ist.

Beispiele

Grundlegende Renderschleife mit WebGL

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });

const startXR = async () => {
  const session = await navigator.xr.requestSession('immersive-vr');
  session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
  const refSpace = await session.requestReferenceSpace('local-floor');

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

    const pose = frame.getViewerPose(refSpace);
    if (!pose) return; // Tracking (noch) nicht verfügbar

    const layer = frame.session.renderState.baseLayer;
    gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    for (const view of pose.views) {
      const vp = layer.getViewport(view);
      gl.viewport(vp.x, vp.y, vp.width, vp.height);
      // drawScene ist deine eigene Zeichenfunktion
      drawScene(view.projectionMatrix, view.transform.inverse.matrix);
    }
  };

  session.requestAnimationFrame(onFrame);
};

document.querySelector('#enter-vr').addEventListener('click', startXR);

Kopfposition und Tracking-Status auslesen

const logViewer = (frame, refSpace) => {
  const pose = frame.getViewerPose(refSpace);
  if (!pose) {
    console.warn('Keine Betrachter-Pose – Tracking verloren?');
    return;
  }
  const { x, y, z } = pose.transform.position;
  console.log(`Kopf bei x=${x.toFixed(2)} y=${y.toFixed(2)} z=${z.toFixed(2)}`);
  console.log('Anzahl Views:', pose.views.length);
  console.log('Position geschätzt:', pose.emulatedPosition);
};
Kopf bei x=0.02 y=1.63 z=-0.10 Anzahl Views: 2 Position geschätzt: false

Betrachter verschieben mit einem versetzten Referenzraum

// Teleport: Der Nutzer soll 2 m weiter vorne stehen
const teleport = (refSpace) => {
  const offset = new XRRigidTransform({ x: 0, y: 0, z: 2 });
  return refSpace.getOffsetReferenceSpace(offset);
};

let viewSpace = await session.requestReferenceSpace('local-floor');
viewSpace = teleport(viewSpace);

session.requestAnimationFrame(function onFrame(t, frame) {
  session.requestAnimationFrame(onFrame);
  const pose = frame.getViewerPose(viewSpace);
  if (pose) console.log(pose.transform.position.z.toFixed(2));
});
-2.00 (ungefähr, je nach Kopfposition)

// Wichtig · Fallstricke

  • Nur im aktiven Frame gültig: Rufe die Methode nur innerhalb des Callbacks von XRSession.requestAnimationFrame() auf. Außerhalb davon oder bei einem gespeicherten, veralteten XRFrame wirft sie eine InvalidStateError-DOMException.
  • Immer auf null prüfen: Bei Tracking-Verlust kommt keine Pose zurück. Ohne Prüfung führt der Zugriff auf pose.views zu einem TypeError.
  • Der Referenzraum muss zur selben Sitzung gehören wie der Frame. Außerdem muss sein Typ bei requestSession() angefordert worden sein (z. B. optionalFeatures: ['local-floor']), sonst schlägt requestReferenceSpace() fehl.
  • Rechne nicht mit einer festen Anzahl an Views. Durchlaufe immer pose.views, denn Smartphone-AR hat einen View, Headsets haben zwei, und manche Geräte haben mehr.
  • Sichere Umgebung: WebXR funktioniert nur über HTTPS (oder localhost). In iframes braucht es die Permissions Policy xr-spatial-tracking.
  • Kompatibilität: Unterstützt in Chromium-Browsern (Chrome, Edge, Samsung Internet), im Meta Quest Browser und in Safari auf visionOS. Firefox und Desktop-Safari unterstützen WebXR nicht. Prüfe vorher mit navigator.xr?.isSessionSupported().
  • Für die Pose anderer Objekte wie Controller oder Hände nimmst du XRFrame.getPose().