Signatur
Beschreibung
Der Konstruktor XRWebGLLayer() erzeugt eine Ebene (Layer), über die ein WebGL- bzw. WebGL2-Kontext die Bilder für ein XR-Gerät (VR-Brille, AR-fähiges Smartphone) liefert. Die Ebene enthält einen eigenen WebGLFramebuffer (layer.framebuffer). In diesen rendert man pro Frame und pro Auge (XRView). Das Gerät zeigt das Ergebnis dann an.
Man benutzt ihn gleich nach dem Start einer Sitzung mit navigator.xr.requestSession(). Die neue Ebene wird über session.updateRenderState({ baseLayer }) als Basisebene festgelegt. Erst danach ruft die Sitzung Frames über requestAnimationFrame() auf und stellt sie dar.
Wichtig: Der WebGL-Kontext muss XR-kompatibel sein. Dafür erzeugt man ihn entweder mit der Option { xrCompatible: true } oder ruft vorher await gl.makeXRCompatible() auf. Außerdem darf die Sitzung noch nicht beendet sein. Mit dem Wörterbuch layerInit legt man fest, ob Tiefenpuffer, Stencil-Puffer, Alpha-Kanal und Antialiasing verwendet werden und wie hoch die Framebuffer-Auflösung ist.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $session Pflicht | XRSession | Die aktive XR-Sitzung, für die die Ebene erzeugt wird. Ist sie schon beendet, wird ein InvalidStateError ausgelöst. |
|
| $context Pflicht | WebGLRenderingContext | WebGL2RenderingContext | Der WebGL-Kontext, der die Bilder rendert. Er muss XR-kompatibel sein (xrCompatible: true oder makeXRCompatible()). Ist das nicht der Fall, wird ein InvalidStateError ausgelöst. |
|
| $layerInit | XRWebGLLayerInit | {} | Optionales Konfigurationsobjekt mit diesen Feldern:
|
Rückgabewert
XRWebGLLayer. Wichtige Eigenschaften sind framebuffer, framebufferWidth und framebufferHeight. Mit der Methode getViewport(view) erhält man den Bildausschnitt für ein bestimmtes Auge.Beispiele
Immersive VR-Sitzung starten und Basisebene setzen
const startVR = async () => {
if (!navigator.xr || !(await navigator.xr.isSessionSupported('immersive-vr'))) {
console.log('WebXR VR wird nicht unterstützt');
return;
}
// Sitzungen müssen durch eine Benutzeraktion (z. B. Klick) gestartet werden
const session = await navigator.xr.requestSession('immersive-vr');
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const layer = new XRWebGLLayer(session, gl);
session.updateRenderState({ baseLayer: layer });
console.log(`Framebuffer: ${layer.framebufferWidth}x${layer.framebufferHeight}`);
return { session, gl };
};
document.querySelector('#vr-button').addEventListener('click', startVR);
Nachträglich XR-kompatibel machen und mit Optionen konfigurieren
const canvas = document.querySelector('#scene');
const gl = canvas.getContext('webgl'); // ohne xrCompatible erzeugt
const enterAR = async () => {
const session = await navigator.xr.requestSession('immersive-ar');
await gl.makeXRCompatible();
const layer = new XRWebGLLayer(session, gl, {
antialias: false, // spart Rechenleistung auf Mobilgeräten
alpha: true, // Kamerabild bleibt sichtbar
framebufferScaleFactor: 0.75 // geringere Auflösung, höhere Bildrate
});
session.updateRenderState({ baseLayer: layer });
console.log('Antialiasing aktiv:', layer.antialias);
};
document.querySelector('#ar-button').addEventListener('click', enterAR);
Render-Schleife: pro Auge in den Framebuffer der Ebene zeichnen
const run = async (session, gl) => {
const refSpace = await session.requestReferenceSpace('local');
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
const layer = session.renderState.baseLayer;
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
gl.bindFramebuffer(gl.FRAMEBUFFER, layer.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 = layer.getViewport(view);
gl.viewport(vp.x, vp.y, vp.width, vp.height);
// hier Szene mit view.projectionMatrix und view.transform zeichnen
}
};
session.requestAnimationFrame(onFrame);
};
// Wichtig · Fallstricke
- XR-Kompatibilität: Ist der Kontext nicht XR-kompatibel, wirft der Konstruktor einen
InvalidStateError. Dasselbe gilt, wenn die Sitzung schon beendet ist oder der WebGL-Kontext verloren wurde (isContextLost()). makeXRCompatible()kann den Kontext auf eine andere GPU verlegen. Dabei geht der Kontext verloren, und alle Texturen, Puffer und Shader müssen neu angelegt werden. Deshalb istxrCompatible: trueschon beim Erzeugen des Kontexts meist die bessere Wahl.framebufferist bei immersiven Sitzungen ein undurchsichtiges Objekt. Man darf es nicht mitdeleteFramebuffer()löschen, und seine Anhänge (Attachments) lassen sich nicht auslesen. Außerhalb eines XR-Frames zu rendern hat keine sichtbare Wirkung.framebufferScaleFactorist nur ein Wunsch an das Gerät. Die tatsächliche Größe steht inframebufferWidth/framebufferHeight.XRWebGLLayer.getNativeFramebufferScaleFactor(session)liefert den Faktor für die native Auflösung.- Kompatibilität: Die WebXR Device API braucht einen sicheren Kontext (HTTPS). Sie wird in Chromium-Browsern und im Meta Quest Browser unterstützt, in Firefox und Safari (Desktop) nicht; Apple Vision Pro unterstützt WebXR teilweise. In iframes ist die Berechtigungsrichtlinie
xr-spatial-trackingnötig. - Für mehrere Ebenen oder Ebenen mit besserer Leistung gibt es die WebXR Layers API (
XRWebGLBinding,XRProjectionLayer). Sie wird jedoch bisher kaum unterstützt.