Start · Sprachen · JavaScript · Referenz · XRView

XRView

Schnittstelle

Beschreibt eine einzelne Ansicht (z. B. ein Auge) in die XR-Szene für einen bestimmten Frame, inklusive Projektionsmatrix und Blickpunkt-Transformation.

seit JavaScript WebXR Device API; Chromium-Browser (Chrome/Edge 79 Kategorie: webapi

Signatur

interface XRView

Beschreibung

XRView steht für einen einzelnen Blickpunkt, von dem aus die XR-Szene in einem bestimmten Frame gerendert werden muss. Bei einem VR-Headset gibt es meist zwei Ansichten (linkes und rechtes Auge), bei Handheld-AR auf dem Smartphone meist nur eine. Man erzeugt XRView-Objekte nicht selbst. Man erhält sie über das Array XRViewerPose.views, das XRFrame.getViewerPose(referenceSpace) liefert.

Die wichtigsten Eigenschaften:

  • eye: "left", "right" oder "none". Gibt an, für welches Auge die Ansicht gedacht ist.
  • projectionMatrix: Eine Float32Array mit 16 Werten (4×4, spaltenweise). Das ist die Projektionsmatrix für den Shader.
  • transform: Ein XRRigidTransform mit Position und Ausrichtung der Ansicht. Die View-Matrix erhält man über transform.inverse.matrix.
  • recommendedViewportScale: Ein empfohlener Skalierungsfaktor für den Viewport (oder null). Man übergibt ihn an requestViewportScale().
  • requestViewportScale(scale): Fordert für diese Ansicht einen kleineren Viewport an, zum Beispiel um bei hoher GPU-Last Leistung zu sparen.

Typisch ist folgender Ablauf: In jedem Frame des requestAnimationFrame-Callbacks der XRSession geht man alle Views durch. Für jede View fragt man mit XRWebGLLayer.getViewport(view) den passenden Viewport ab, setzt Projektions- und View-Matrix und zeichnet die Szene. So entsteht stereoskopisches Rendering, das zur Kopfposition passt.

Parameter

Name Typ Default Beschreibung
$scale number | null Nur für requestViewportScale(scale): gewünschte Viewport-Skalierung im Bereich (0, 1]. Werte außerhalb dieses Bereichs oder null werden ignoriert.

Rückgabewert

Typ
XRView
Beschreibung
Wird nicht vom Konstruktor erzeugt, sondern über XRViewerPose.views bereitgestellt. Es gibt keinen öffentlichen Konstruktor. requestViewportScale() gibt undefined zurück.

Beispiele

Views eines Frames durchlaufen und rendern

// gl: WebGL2-Kontext, der mit xrCompatible: true erstellt wurde
const session = await navigator.xr.requestSession('immersive-vr');
await gl.makeXRCompatible();
const layer = new XRWebGLLayer(session, gl);
session.updateRenderState({ baseLayer: layer });
const refSpace = await session.requestReferenceSpace('local');

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return; // Tracking verloren

  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 die eigene Render-Funktion
    drawScene(view.projectionMatrix, view.transform.inverse.matrix);
  }
};
session.requestAnimationFrame(onFrame);

Auge und Kameraposition auslesen

const logViews = (frame, refSpace) => {
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;
  for (const view of pose.views) {
    const { x, y, z } = view.transform.position;
    console.log(`${view.eye}: (${x.toFixed(3)}, ${y.toFixed(3)}, ${z.toFixed(3)})`);
  }
};
left: (-0.032, 1.600, 0.000) right: (0.032, 1.600, 0.000)

Dynamische Viewport-Skalierung nutzen

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;
  for (const view of pose.views) {
    // Empfehlung des Geräts übernehmen, falls vorhanden
    if (view.recommendedViewportScale) {
      view.requestViewportScale(view.recommendedViewportScale);
    }
    // Wichtig: getViewport erst NACH requestViewportScale aufrufen
    const vp = layer.getViewport(view);
    gl.viewport(vp.x, vp.y, vp.width, vp.height);
    drawScene(view.projectionMatrix, view.transform.inverse.matrix);
  }
};

// Wichtig · Fallstricke

  • Nur innerhalb des Frames gültig: XRView-Objekte gehören zum jeweiligen XRFrame. Man sollte sie nicht über den Animation-Callback hinaus speichern. Pose und Views müssen in jedem Frame neu abgefragt werden.
  • transform ist keine View-Matrix: transform.matrix beschreibt die Pose der Kamera. Für den Shader braucht man die Inverse, also transform.inverse.matrix.
  • Anzahl der Views nicht fest verdrahten: Je nach Gerät gibt es 1, 2 oder mehr Views. Deshalb immer über pose.views iterieren und eye nicht als gegeben voraussetzen.
  • getViewerPose() kann null liefern, etwa wenn das Tracking noch nicht bereit ist. Das muss man abfangen.
  • requestViewportScale() wirkt nur, wenn man danach im selben Frame getViewport() aufruft. Die Methode wird nicht überall unterstützt.
  • Kompatibilität: WebXR erfordert einen sicheren Kontext (HTTPS). Unterstützung gibt es in Chromium-Browsern und im Meta Quest Browser. Firefox unterstützt WebXR nicht, Safari nur auf visionOS. Vorher mit navigator.xr?.isSessionSupported() prüfen.