Signatur
Beschreibung
Die Eigenschaft width eines XRViewport-Objekts liefert die Breite des Rechtecks in Pixeln, in das eine bestimmte XRView (z. B. das linke oder rechte Auge) gerendert werden soll. Zusammen mit x, y und height beschreibt sie genau den Ausschnitt des Framebuffers, den der Browser für diese Ansicht vorsieht.
Einen Viewport erhältst du normalerweise pro Frame über XRWebGLLayer.getViewport(view) oder, mit der WebXR-Layers-API, über XRWebGLBinding.getViewSubImage(). Die Werte übergibst du direkt an gl.viewport(x, y, width, height) (und ggf. an gl.scissor()), bevor du die Szene für die jeweilige Ansicht zeichnest.
Bei stereoskopischer Darstellung teilen sich meist zwei Viewports einen Framebuffer, der nebeneinander aufgeteilt ist. width entspricht dann ungefähr der halben Framebuffer-Breite. Leg diese Aufteilung aber nicht selbst fest: Die Aufteilung bestimmt allein der Browser bzw. das XR-Gerät.
Rückgabewert
Beispiele
Viewport pro Auge im Render-Loop setzen
const onXRFrame = (time, frame) => {
const session = frame.session;
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(xrRefSpace);
if (!pose) return;
const layer = 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);
// Zeichenbereich auf den Viewport dieser Ansicht beschränken
gl.viewport(vp.x, vp.y, vp.width, vp.height);
drawScene(view.projectionMatrix, view.transform.inverse.matrix);
}
};
Seitenverhältnis für eigene Projektion berechnen
const getAspect = (layer, view) => {
const { width, height } = layer.getViewport(view);
return height > 0 ? width / height : 1;
};
// z. B. für ein 2D-Overlay oder einen Post-Processing-Pass
const aspect = getAspect(session.renderState.baseLayer, pose.views[0]);
console.log(`Seitenverhältnis: ${aspect.toFixed(3)}`);
Viewport-Größen zur Fehlersuche protokollieren
const logViewports = (frame, refSpace) => {
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
const layer = frame.session.renderState.baseLayer;
pose.views.forEach((view) => {
const vp = layer.getViewport(view);
console.log(`${view.eye}: ${vp.width}×${vp.height} @ (${vp.x}, ${vp.y})`);
});
console.log('Framebuffer:', layer.framebufferWidth, '×', layer.framebufferHeight);
};
// Wichtig · Fallstricke
- Schreibgeschützt: Eine Zuweisung an
widthwird ignoriert (im Strict Mode wirft sie einenTypeError). Die Auflösung beeinflusst du überframebufferScaleFactorbeim Erzeugen desXRWebGLLayeroder überXRView.requestViewportScale(). - Nicht zwischenspeichern: Hol den Viewport in jedem Frame neu. Durch dynamische Viewport-Skalierung, Änderungen an
renderStateoder den Wechsel des Layers kann sich die Größe ändern. - Nicht mit der Canvas-Größe verwechseln:
widthbezieht sich auf den XR-Framebuffer (layer.framebufferWidth), nicht aufcanvas.widthoder CSS-Pixel. - Nur in einem sicheren Kontext (HTTPS) verfügbar. Die Unterstützung beschränkt sich im Wesentlichen auf Chromium-Browser und XR-Headset-Browser. Prüfe vorher mit
navigator.xr?.isSessionSupported(), ob die API verfügbar ist.