Start · Sprachen · JavaScript · Referenz · XRView.requestViewportScale()

XRView.requestViewportScale()

Methode

Fordert den Browser auf, den Viewport dieser <code>XRView</code> mit einem Skalierungsfaktor zwischen 0 und 1 zu verkleinern. So lässt sich die Renderlast in WebXR dynamisch senken.

seit JavaScript WebXR Dynamic Viewport Scaling – experimentell (Ch Kategorie: webapi

Signatur

XRView.prototype.requestViewportScale(scale)

Beschreibung

Mit requestViewportScale() gibt eine WebXR-Anwendung an, dass sie für eine bestimmte Ansicht (XRView) nur einen Teil der vollen Framebuffer-Auflösung nutzen möchte. Der Faktor wirkt auf Breite und Höhe des Viewports. Beim Wert 0.5 wird also nur etwa ein Viertel der Pixel berechnet. Das ist nützlich, wenn die GPU die Bildrate nicht halten kann. Eine niedrige Bildrate stört in VR/AR deutlich mehr als eine etwas geringere Schärfe.

Die Methode ändert den Viewport nicht sofort. Der Faktor wird erst beim nächsten Aufruf von XRWebGLLayer.getViewport() (bzw. XRWebGLBinding.getViewSubImage()) für diese Ansicht angewendet. Deshalb muss man sie innerhalb des Frame-Callbacks vor getViewport() aufrufen. Der Browser kann den Wert runden oder auf ein Minimum begrenzen, das er unterstützt. Welcher Viewport tatsächlich gilt, zeigt immer erst das Ergebnis von getViewport().

Oft wird der Wert aus der Eigenschaft XRView.recommendedViewportScale übernommen. Dort schlägt der Browser einen Faktor vor, der auf seinen eigenen Leistungsmessungen beruht. Alternativ misst die Anwendung selbst, z. B. die Frame-Zeiten, und passt den Faktor daraufhin an.

Parameter

Name Typ Default Beschreibung
$scale Pflicht number | null Gewünschter Skalierungsfaktor. Sinnvoll sind Werte größer als 0 bis einschließlich 1 (volle Größe). Werte über 1 werden auf 1 begrenzt. Bei null, undefined oder Werten ≤ 0 wird der Aufruf ignoriert.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Die Änderung sieht man erst am Viewport, den getViewport() danach zurückgibt.

Beispiele

Empfohlenen Skalierungsfaktor des Browsers übernehmen

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

  const glLayer = session.renderState.baseLayer;
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;

  gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  for (const view of pose.views) {
    // Vor getViewport() aufrufen, sonst gilt der Faktor erst im nächsten Frame
    if (view.recommendedViewportScale) {
      view.requestViewportScale(view.recommendedViewportScale);
    }
    const vp = glLayer.getViewport(view);
    gl.viewport(vp.x, vp.y, vp.width, vp.height);
    drawScene(view); // eigene Render-Funktion
  }
};

Eigene dynamische Skalierung anhand der Frame-Zeit

let scale = 1.0;
let lastTime = 0;
const TARGET_MS = 1000 / 72; // z. B. 72 Hz Headset

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

  // Zu langsam: Auflösung senken, genug Reserve: Auflösung wieder erhöhen
  if (delta > TARGET_MS * 1.1) scale = Math.max(0.5, scale - 0.05);
  else if (delta < TARGET_MS * 0.9) scale = Math.min(1.0, scale + 0.02);

  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;
  const glLayer = frame.session.renderState.baseLayer;

  for (const view of pose.views) {
    view.requestViewportScale(scale);
    const { x, y, width, height } = glLayer.getViewport(view);
    gl.viewport(x, y, width, height);
    drawScene(view);
  }
};

Unterstützung vor der Nutzung prüfen

const supportsViewportScale =
  typeof XRView !== 'undefined' &&
  'requestViewportScale' in XRView.prototype;

console.log(supportsViewportScale
  ? 'Dynamische Viewport-Skalierung verfügbar'
  : 'Nicht unterstützt – volle Auflösung wird verwendet');
Dynamische Viewport-Skalierung verfügbar

// Wichtig · Fallstricke

  • Reihenfolge beachten: Der Faktor gilt erst beim nächsten getViewport() für diese Ansicht. Wird er danach gesetzt, wirkt er erst im folgenden Frame.
  • Nur ein Wunsch: Der Browser darf den Wert runden, nach unten begrenzen oder ganz ignorieren. Verlasse dich immer auf den zurückgegebenen XRViewport und nie auf eigene Rechnungen.
  • Kein neuer Framebuffer: Nur der genutzte Bereich wird kleiner, die Größe des Framebuffers bleibt gleich. Wer einmalig eine niedrigere Auflösung möchte, nutzt besser framebufferScaleFactor beim Erzeugen des XRWebGLLayer.
  • recommendedViewportScale kann null sein. Prüfe den Wert deshalb vor der Übergabe.
  • Die Methode gehört zum Modul „WebXR Dynamic Viewport Scaling“ und ist experimentell. Unterstützt wird sie vor allem in Chromium-basierten Browsern (Chrome für Android, Meta Quest Browser), nicht aber in Firefox und Safari. Prüfe die Unterstützung vorher (Feature-Detection). WebXR läuft außerdem nur in sicheren Kontexten (HTTPS).