Start · Sprachen · JavaScript · Referenz · XRSession.updateRenderState()

XRSession.updateRenderState()

Methode

Plant Änderungen am Render-Zustand (<code>XRRenderState</code>) einer XR-Sitzung, die beim nächsten Frame wirksam werden – z. B. Ziel-Layer, Clipping-Ebenen oder Sichtfeld.

seit JavaScript WebXR Device API; Chromium-Browser 79+, Meta Quest Kategorie: webapi

Signatur

XRSession.prototype.updateRenderState(state)

Beschreibung

Mit updateRenderState() legst du fest, wie eine XRSession rendert. Die wichtigste Einstellung ist baseLayer. Das ist ein XRWebGLLayer, der den WebGL-Kontext mit dem XR-Gerät verbindet. Solange kein baseLayer (bzw. keine layers) gesetzt ist, liefert die Sitzung keine Frames aus, die sich darstellen lassen. Deshalb rufst du die Methode praktisch immer direkt nach navigator.xr.requestSession() auf.

Die Änderungen gelten nicht sofort. Sie werden als „ausstehender Render-Zustand“ vorgemerkt und erst übernommen, bevor der nächste requestAnimationFrame-Callback der Sitzung ausgeführt wird. Das aktuelle session.renderState zeigt bis dahin noch die alten Werte. Rufst du die Methode mehrmals vor dem nächsten Frame auf, werden die Angaben zusammengeführt. Nicht angegebene Eigenschaften behalten ihren bisherigen Wert.

Außer dem Ziel-Layer kannst du die Clipping-Ebenen (depthNear, depthFar) und bei inline-Sitzungen das vertikale Sichtfeld (inlineVerticalFieldOfView) anpassen. Mit dem WebXR-Layers-Modul kommt die Eigenschaft layers für mehrere Kompositions-Layer hinzu.

Parameter

Name Typ Default Beschreibung
$state XRRenderStateInit {} Objekt mit den zu ändernden Eigenschaften:
  • baseLayer (XRWebGLLayer): Ziel-Layer für das Rendering.
  • depthNear (number): Abstand der nahen Clipping-Ebene in Metern (Standard 0.1).
  • depthFar (number): Abstand der fernen Clipping-Ebene in Metern (Standard 1000).
  • inlineVerticalFieldOfView (number): vertikales Sichtfeld im Bogenmaß, nur bei inline-Sitzungen (Standard Math.PI / 2).
  • layers (XRLayer[]): geordnete Liste von Layern (WebXR Layers API). Darf nicht zusammen mit baseLayer angegeben werden.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Die Änderungen werden beim nächsten Frame übernommen.

Beispiele

Immersive VR-Sitzung mit WebGL-Layer starten

const startVR = async () => {
  if (!(await navigator.xr?.isSessionSupported('immersive-vr'))) {
    console.log('immersive-vr wird nicht unterstützt');
    return;
  }
  // Muss durch eine Benutzeraktion ausgelöst werden (z. B. Klick)
  const session = await navigator.xr.requestSession('immersive-vr');

  const canvas = document.createElement('canvas');
  const gl = canvas.getContext('webgl2', { xrCompatible: true });

  // Ohne baseLayer werden keine Frames gerendert
  session.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  const refSpace = await session.requestReferenceSpace('local');

  const onFrame = (time, frame) => {
    session.requestAnimationFrame(onFrame);
    const layer = session.renderState.baseLayer;
    gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
    gl.clearColor(0.1, 0.2, 0.3, 1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    // ... Szene pro XRView zeichnen
  };
  session.requestAnimationFrame(onFrame);
};

document.querySelector('#enter-vr').addEventListener('click', startVR);

Clipping-Ebenen anpassen – Übernahme erst beim nächsten Frame

const setClipping = (session) => {
  session.updateRenderState({ depthNear: 0.05, depthFar: 200 });

  // Noch der alte Wert
  console.log(session.renderState.depthFar);

  session.requestAnimationFrame(() => {
    // Jetzt gilt der neue Wert
    console.log(session.renderState.depthFar);
  });
};
1000 200

Sichtfeld einer Inline-Sitzung ändern (Zoom)

const initInline = async (canvas) => {
  const session = await navigator.xr.requestSession('inline');
  const gl = canvas.getContext('webgl', { xrCompatible: true });

  session.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl),
    inlineVerticalFieldOfView: Math.PI / 3 // 60°
  });

  // Zoom per Mausrad
  canvas.addEventListener('wheel', (e) => {
    const current = session.renderState.inlineVerticalFieldOfView;
    const next = Math.min(Math.max(current + e.deltaY * 0.001, 0.3), 2.5);
    session.updateRenderState({ inlineVerticalFieldOfView: next });
  });

  return session;
};

// Wichtig · Fallstricke

  • Ausnahmen: InvalidStateError, wenn die Sitzung schon beendet ist, wenn baseLayer von einer anderen Sitzung stammt oder wenn inlineVerticalFieldOfView bei einer immersiven Sitzung gesetzt wird. NotSupportedError, wenn layers ohne aktivierte Layers-Funktion ('layers' als Feature) verwendet wird. TypeError, wenn baseLayer und layers gleichzeitig angegeben werden.
  • Der WebGL-Kontext muss XR-kompatibel sein: Erzeuge ihn mit { xrCompatible: true } oder rufe vorher await gl.makeXRCompatible() auf. Sonst wirft der XRWebGLLayer-Konstruktor einen Fehler.
  • Lies nach dem Aufruf nicht sofort aus session.renderState. Die neuen Werte stehen erst im nächsten Frame-Callback bereit.
  • depthNear und depthFar müssen zu deiner Projektions- bzw. Tiefenpuffer-Logik passen. Die Projektionsmatrizen in XRView.projectionMatrix werden aus diesen Werten berechnet.
  • Kompatibilität: WebXR gibt es nur in sicheren Kontexten (HTTPS). Unterstützt wird es in Chromium-Browsern (Chrome, Edge, Samsung Internet) und im Meta Quest Browser. Firefox und Safari auf dem Desktop unterstützen es nicht. Mit einer Weiche wie navigator.xr?.isSessionSupported() fängst du fehlende Unterstützung ab.