Signatur
Beschreibung
Jeder XRFrame wird von genau einer XRSession erzeugt und an den Rückruf von XRSession.requestAnimationFrame() übergeben. Über frame.session erreicht man diese Sitzung direkt, ohne sie in einer äußeren Variablen oder einem Closure speichern zu müssen.
Gebraucht wird das vor allem in der Render-Schleife. Dort muss man den nächsten Frame mit session.requestAnimationFrame() anfordern, auf session.renderState.baseLayer (den XRWebGLLayer mit Framebuffer und Viewports) zugreifen oder Eingabequellen über session.inputSources auslesen. Ein Callback, der nur frame.session verwendet, lässt sich ohne Änderungen für mehrere Sitzungen einsetzen.
Die Eigenschaft ist schreibgeschützt und gibt für einen bestimmten Frame immer dieselbe Sitzung zurück. Man kann die Referenz auch außerhalb des Callbacks behalten, aber die meisten Frame-Methoden wie getViewerPose() oder getPose() funktionieren nur, solange der Frame aktiv ist, also während des Callbacks.
Rückgabewert
XRSession-Objekt, das diesen Frame erzeugt hat.Beispiele
Render-Schleife ohne globale Sitzungsvariable
const onXRFrame = (time, frame) => {
const session = frame.session;
// Nächsten Frame direkt über die Sitzung des Frames anfordern
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
const glLayer = session.renderState.baseLayer;
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
for (const view of pose.views) {
const vp = glLayer.getViewport(view);
gl.viewport(vp.x, vp.y, vp.width, vp.height);
// drawScene(view) ...
}
};
let refSpace;
const gl = document.createElement('canvas').getContext('webgl2', { xrCompatible: true });
const startXR = async () => {
const session = await navigator.xr.requestSession('immersive-vr');
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
refSpace = await session.requestReferenceSpace('local');
session.requestAnimationFrame(onXRFrame);
};
document.querySelector('#vr-button').addEventListener('click', startXR);
Eingabequellen im Frame auswerten
const handleInput = (frame, refSpace) => {
for (const source of frame.session.inputSources) {
if (!source.gripSpace) continue;
const gripPose = frame.getPose(source.gripSpace, refSpace);
if (gripPose) {
const { x, y, z } = gripPose.transform.position;
console.log(`${source.handedness}: ${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)}`);
}
}
};
Sitzung aus dem Frame heraus beenden
const MAX_DURATION_MS = 60_000;
let startTime = null;
const onXRFrame = (time, frame) => {
startTime ??= time;
if (time - startTime > MAX_DURATION_MS) {
// Keinen weiteren Frame anfordern, Sitzung beenden
frame.session.end().then(() => console.log('XR-Sitzung beendet'));
return;
}
frame.session.requestAnimationFrame(onXRFrame);
};
// Wichtig · Fallstricke
- Frame-Gültigkeit:
frame.sessionbleibt auch nach dem Callback abrufbar. Methoden wiegetViewerPose()odergetPose()werfen dagegen außerhalb des aktiven Callbacks einenInvalidStateError. Frames sollten deshalb nicht für spätere Nutzung gespeichert werden. - Beendete Sitzungen: Nach
session.end()oder dem Ereignisendverweist die Eigenschaft weiterhin auf die inzwischen beendete Sitzung. Neue Frames werden dann nicht mehr ausgeliefert. - Kompatibilität: WebXR funktioniert nur in einem sicheren Kontext (HTTPS) und ist hauptsächlich in Chromium-Browsern und auf XR-Headsets verfügbar. Vorher mit
navigator.xr?.isSessionSupported()prüfen, ob der gewünschte Sitzungsmodus unterstützt wird. - Die Eigenschaft ist schreibgeschützt. Eine Zuweisung wird ignoriert bzw. wirft im Strict Mode einen
TypeError.