Signatur
Beschreibung
Die schreibgeschützte Eigenschaft renderState eines XRSession-Objekts gibt ein XRRenderState-Objekt zurück. Es beschreibt, wie die Szene für die Sitzung gerendert wird: depthNear und depthFar (Clipping-Ebenen), inlineVerticalFieldOfView (nur bei inline-Sitzungen), baseLayer (ein XRWebGLLayer, in den gezeichnet wird) sowie – mit dem WebXR-Layers-Modul – layers.
Das Objekt selbst ist unveränderlich. Um Werte zu ändern, ruft man XRSession.updateRenderState() mit einem Wörterbuch der neuen Werte auf. Die Änderungen werden nicht sofort übernommen, sondern erst zu Beginn des nächsten Animations-Frames; erst dann gibt renderState ein neues Objekt mit den aktualisierten Werten zurück.
Typischerweise liest man renderState innerhalb des Frame-Callbacks von requestAnimationFrame(), um z. B. an den Framebuffer des baseLayer zu gelangen oder die Projektionsmatrix passend zu den Tiefenwerten zu berechnen.
Rückgabewert
baseLayer, depthNear, depthFar, inlineVerticalFieldOfView und ggf. layers.Beispiele
Sitzung starten und baseLayer setzen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const startXR = async () => {
const session = await navigator.xr.requestSession('immersive-vr');
// Neuen Render-Zustand anfordern
session.updateRenderState({
baseLayer: new XRWebGLLayer(session, gl),
depthNear: 0.1,
depthFar: 100
});
// Direkt danach ist der alte Zustand noch aktiv
console.log(session.renderState.baseLayer); // null
const refSpace = await session.requestReferenceSpace('local');
session.requestAnimationFrame((time, frame) => {
// Jetzt ist der neue Zustand übernommen
console.log(session.renderState.depthNear, session.renderState.depthFar);
});
};
document.querySelector('#enter-vr').addEventListener('click', startXR);
Framebuffer im Render-Loop verwenden
const onXRFrame = (time, frame) => {
const session = frame.session;
session.requestAnimationFrame(onXRFrame);
const { baseLayer } = session.renderState;
gl.bindFramebuffer(gl.FRAMEBUFFER, baseLayer.framebuffer);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
for (const view of pose.views) {
const vp = baseLayer.getViewport(view);
gl.viewport(vp.x, vp.y, vp.width, vp.height);
// drawScene(view.projectionMatrix, view.transform.inverse.matrix);
}
};
Sichtfeld einer Inline-Sitzung auslesen
const session = await navigator.xr.requestSession('inline');
session.updateRenderState({
baseLayer: new XRWebGLLayer(session, gl),
inlineVerticalFieldOfView: Math.PI / 3
});
session.requestAnimationFrame(() => {
const fovGrad = session.renderState.inlineVerticalFieldOfView * 180 / Math.PI;
console.log(`Vertikales Sichtfeld: ${fovGrad.toFixed(0)}°`);
});
// Wichtig · Fallstricke
- Verzögerte Übernahme: Nach
updateRenderState()liefertrenderStatebis zum nächsten Frame noch den alten Zustand. Verlass dich also nicht darauf, dass die Werte direkt danach schon übernommen sind. - Zu Beginn einer Sitzung ist
baseLayernull. Solange kein Layer gesetzt ist, werden keine Frame-Callbacks ausgeführt. - Bei immersiven Sitzungen ist
inlineVerticalFieldOfViewnull. Wenn du den Wert dort perupdateRenderState()setzt, wird einInvalidStateErrorausgelöst. - Speichere das Objekt nicht dauerhaft zwischen. Frag
session.renderStatein jedem Frame neu ab, weil nach jeder Änderung ein neues Objekt entsteht. - Kompatibilität: WebXR funktioniert nur in sicheren Kontexten (HTTPS) und wird in Chromium-Browsern sowie auf XR-Headsets unterstützt. Firefox und Safari auf dem Desktop unterstützen WebXR nicht. Nach dem Ende der Sitzung (Ereignis
end) solltest du den Zustand nicht mehr verwenden.