Start · Sprachen · JavaScript · Referenz · XRViewport.x

XRViewport.x

Eigenschaft

Schreibgeschützte Ganzzahl: horizontaler Versatz in Pixeln von der linken Kante der Zieloberfläche (z. B. <code>XRWebGLLayer</code>) bis zur linken Kante des Viewports.

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

Signatur

XRViewport.x

Beschreibung

Die schreibgeschützte Eigenschaft x eines XRViewport-Objekts gibt den horizontalen Versatz in Pixeln an. Gemessen wird von der linken Kante der Zieloberfläche, meist dem Framebuffer eines XRWebGLLayer, bis zur linken Kante des Bereichs, in den eine bestimmte XRView gerendert werden soll.

Bei stereoskopischen Geräten (VR-Headsets) teilen sich meist beide Augen einen Framebuffer. Das linke Auge beginnt dann typischerweise bei x = 0, das rechte bei x = framebufferWidth / 2. Man bekommt den Viewport über XRWebGLLayer.getViewport(view) und reicht x zusammen mit y, width und height direkt an gl.viewport() weiter.

Den Wert selbst zu berechnen, ist keine gute Idee. Übernimm immer den Wert, den der Browser pro Frame und pro View liefert: Aufteilung und Auflösung des Framebuffers hängen vom Gerät ab und können sich während einer Sitzung ändern, etwa durch dynamische Viewport-Skalierung.

Rückgabewert

Typ
number
Beschreibung
Ganzzahliger Versatz in Pixeln (long) von der linken Kante der Zieloberfläche bis zur linken Kante des Viewports.

Beispiele

Viewport pro Auge im Render-Loop setzen

// Voraussetzung: xrSession läuft, gl ist ein XR-kompatibler WebGL-Kontext
const onXRFrame = (time, frame) => {
  const session = frame.session;
  session.requestAnimationFrame(onXRFrame);

  const pose = frame.getViewerPose(xrRefSpace);
  if (!pose) return;

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

  for (const view of pose.views) {
    const vp = glLayer.getViewport(view);
    // x und y legen die Position innerhalb des Framebuffers fest
    gl.viewport(vp.x, vp.y, vp.width, vp.height);
    drawScene(view.projectionMatrix, view.transform.inverse.matrix);
  }
};

xrSession.requestAnimationFrame(onXRFrame);

Aufteilung des Framebuffers ausgeben

const logViewports = (frame, refSpace) => {
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;
  const layer = frame.session.renderState.baseLayer;

  for (const view of pose.views) {
    const { x, y, width, height } = layer.getViewport(view);
    console.log(`${view.eye}: x=${x}, y=${y}, ${width}×${height}`);
  }
  console.log(`Framebuffer: ${layer.framebufferWidth}×${layer.framebufferHeight}`);
};
left: x=0, y=0, 1832×1920 right: x=1832, y=0, 1832×1920 Framebuffer: 3664×1920

Scissor-Test auf den Viewport begrenzen

// Verhindert, dass clear() in den Bereich des anderen Auges schreibt
const clearView = (gl, vp) => {
  gl.enable(gl.SCISSOR_TEST);
  gl.scissor(vp.x, vp.y, vp.width, vp.height);
  gl.viewport(vp.x, vp.y, vp.width, vp.height);
  gl.clearColor(0.1, 0.1, 0.15, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.disable(gl.SCISSOR_TEST);
};

// Wichtig · Fallstricke

  • Schreibgeschützt: Eine Zuweisung an x hat keine Wirkung (im Strict Mode gibt es einen TypeError). Wenn du eine andere Auflösung willst, nutze XRWebGLLayer-Optionen wie framebufferScaleFactor oder XRView.requestViewportScale().
  • Nicht zwischenspeichern: Hol dir den Viewport in jedem Frame neu über getViewport(). Die Werte können sich zwischen Frames ändern.
  • Koordinatenursprung: x zählt wie in WebGL von links. Bei y liegt der Ursprung dagegen unten links (WebGL-Konvention), nicht oben wie im DOM.
  • Bei Mono-Darstellung (z. B. inline-Sitzungen oder AR auf dem Smartphone) ist x meist 0.
  • Kompatibilität: WebXR steht nur in sicheren Kontexten (HTTPS) zur Verfügung und wird im Wesentlichen von Chromium-Browsern und Headset-Browsern unterstützt. Prüfe die Unterstützung vorher mit navigator.xr?.isSessionSupported().