Signatur
Beschreibung
XRWebGLLayer.framebuffer liefert den Framebuffer, in den eine immersive WebXR-Sitzung (immersive-vr oder immersive-ar) ihre Bilder rendern muss. Der Browser legt ihn selbst an und verwaltet ihn. Der XR-Kompositor liest das Ergebnis am Ende jedes Frames aus und zeigt es auf dem Headset oder dem AR-Display an.
Es handelt sich um einen undurchsichtigen (opaken) Framebuffer. Er verhält sich weitgehend wie ein normales WebGLFramebuffer, hat aber einige Einschränkungen: Seine Anhänge (Farbe, Tiefe, Stencil) lassen sich weder abfragen noch ändern, und er ist nur innerhalb eines Callbacks von XRSession.requestAnimationFrame() vollständig (FRAMEBUFFER_COMPLETE). Seine Größe liest man über framebufferWidth und framebufferHeight aus. Welchen Bereich jede Ansicht (linkes oder rechtes Auge) belegt, liefert getViewport(view).
Üblicherweise bindet man den Framebuffer einmal pro Frame mit gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer), leert ihn und zeichnet dann jede Ansicht in ihren eigenen Viewport. Wurde die Ebene ohne Komposition erzeugt, etwa in einer inline-Sitzung, ist der Wert null. In dem Fall rendert man ganz normal in den Standard-Framebuffer des Canvas, indem man null bindet.
Rückgabewert
null, wenn die Ebene ohne XR-Komposition arbeitet (z. B. in inline-Sitzungen). Dann wird in den Standard-Framebuffer des Canvas gerendert.Beispiele
Render-Schleife: Framebuffer binden und pro Auge zeichnen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const session = await navigator.xr.requestSession('immersive-vr');
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;
const glLayer = session.renderState.baseLayer;
// In den Framebuffer des Kompositors rendern
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
gl.clearColor(0.1, 0.1, 0.2, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
for (const view of pose.views) {
const vp = glLayer.getViewport(view);
gl.viewport(vp.x, vp.y, vp.width, vp.height);
// drawScene(view.projectionMatrix, view.transform.inverse.matrix);
}
};
session.requestAnimationFrame(onFrame);
null bei inline-Sitzungen berücksichtigen
const bindXRTarget = (gl, session) => {
const layer = session.renderState.baseLayer;
// Ist framebuffer null, zeigt bindFramebuffer(null) auf den Canvas
gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
console.log(layer.framebuffer ? 'XR-Kompositor' : 'Standard-Framebuffer (Canvas)');
};
const gl = document.querySelector('canvas').getContext('webgl', { xrCompatible: true });
const session = await navigator.xr.requestSession('inline');
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
bindXRTarget(gl, session);
Vollständigkeit prüfen (nur im Frame-Callback gültig)
session.requestAnimationFrame((time, frame) => {
const fb = session.renderState.baseLayer.framebuffer;
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log(status === gl.FRAMEBUFFER_COMPLETE);
});
// Wichtig · Fallstricke
- Nur im Frame-Callback nutzbar: Außerhalb eines Callbacks von
XRSession.requestAnimationFrame()liefertcheckFramebufferStatus()den WertFRAMEBUFFER_UNSUPPORTED. Zeichenaufrufe bleiben dann wirkungslos. - Keine Änderung der Anhänge: Aufrufe wie
framebufferTexture2D(),framebufferRenderbuffer(),getFramebufferAttachmentParameter()oderdeleteFramebuffer()auf diesem Framebuffer lösenINVALID_OPERATIONaus. - Inhalt wird jeden Frame geleert: Der Browser leert den Framebuffer zu Beginn jedes XR-Frames. Inhalte aus dem vorherigen Frame lassen sich nicht wiederverwenden.
- Viewport nicht vergessen: Beide Augen teilen sich in der Regel einen Framebuffer. Ohne
gl.viewport()mit den Werten ausgetViewport(view)landet das Bild im falschen Bereich. - Nach einem eigenen Render-Pass in ein anderes Ziel (z. B. Offscreen-Textur) muss
layer.framebufferwieder gebunden werden, bevor die endgültige Szene gezeichnet wird. - Browser-Unterstützung: WebXR steht nur in sicheren Kontexten (HTTPS) zur Verfügung. Unterstützt wird es vor allem in Chromium-Browsern und auf Standalone-Headsets, nicht in Firefox und Safari auf dem Desktop. Vor der Nutzung mit
navigator.xr?.isSessionSupported()prüfen.