Start · Sprachen · JavaScript · Referenz · XRWebGLBinding.createProjectionLayer()

XRWebGLBinding.createProjectionLayer()

Methode

Erzeugt einen <code>XRProjectionLayer</code>, der die gesamte Sicht des Betrachters ausfüllt und mit nahezu nativer Bildrate des XR-Geräts aktualisiert wird.

seit JavaScript WebXR Layers API – Meta Quest Browser, Chromium (t Kategorie: webapi

Signatur

XRWebGLBinding.prototype.createProjectionLayer(options)

Beschreibung

Die Methode createProjectionLayer() des Interfaces XRWebGLBinding legt eine Projektionsebene (XRProjectionLayer) an. Eine Projektionsebene deckt das komplette Sichtfeld ab und wird für jedes Auge (jede XRView) passend gerendert. Sie ersetzt in der WebXR Layers API die klassische XRWebGLLayer als Hauptebene für die 3D-Szene.

Im Unterschied zu XRWebGLLayer gibt es keinen gemeinsamen Framebuffer. Das XR-System stellt stattdessen Texturen bereit. Diese holst du pro Frame und pro View mit XRWebGLBinding.getViewSubImage() und hängst sie an einen eigenen Framebuffer an. Mit textureType: "texture-array" lassen sich beide Augen in einer Array-Textur ablegen. Das ist die Grundlage für Multiview-Rendering (OVR_multiview2), das die GPU deutlich weniger belastet.

Voraussetzung ist eine XR-Sitzung, die mit dem Feature "layers" angefordert wurde. Die erzeugte Ebene wird erst sichtbar, wenn du sie über XRSession.updateRenderState({ layers: [...] }) in die Ebenenliste der Sitzung einträgst. Dort kannst du sie mit weiteren Ebenen kombinieren, zum Beispiel mit Quad-, Zylinder- oder Kugelebenen für scharfen Text oder Videos.

Parameter

Name Typ Default Beschreibung
$options object {} Optionales Konfigurationsobjekt (XRProjectionLayerInit) mit den folgenden Eigenschaften.
$options.textureType "texture" | "texture-array" "texture" "texture" liefert eine 2D-Textur pro View. "texture-array" liefert eine TEXTURE_2D_ARRAY mit einer Schicht pro View. Das setzt WebGL2 voraus und eignet sich für Multiview.
$options.colorFormat GLenum gl.RGBA8 (0x8058) Internes Format der Farbtextur, z. B. gl.RGBA8 oder gl.SRGB8_ALPHA8.
$options.depthFormat GLenum gl.DEPTH_COMPONENT (0x1902) Internes Format der Tiefen-/Stencil-Textur, z. B. gl.DEPTH_COMPONENT24 oder gl.DEPTH24_STENCIL8. Mit 0 wird keine Tiefentextur angelegt.
$options.scaleFactor number 1.0 Skalierungsfaktor für die Texturauflösung, bezogen auf die empfohlene Auflösung des Geräts. Werte unter 1 verbessern die Leistung, machen das Bild aber unschärfer.

Rückgabewert

Typ
XRProjectionLayer
Beschreibung
Eine neue Projektionsebene. Ihre Texturen erhältst du pro Frame über XRWebGLBinding.getViewSubImage(layer, view).

Beispiele

Sitzung mit Layers-Feature starten und Projektionsebene setzen

const startXR = async () => {
  const session = await navigator.xr.requestSession('immersive-vr', {
    requiredFeatures: ['layers']
  });

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

  const binding = new XRWebGLBinding(session, gl);
  const projLayer = binding.createProjectionLayer({
    textureType: 'texture',
    colorFormat: gl.RGBA8,
    depthFormat: gl.DEPTH_COMPONENT24
  });

  // Ebene aktivieren – ersetzt baseLayer
  session.updateRenderState({ layers: [projLayer] });
  console.log('Texturgröße:', projLayer.textureWidth, 'x', projLayer.textureHeight);

  return { session, gl, binding, projLayer };
};

startXR();
Texturgröße: 1832 x 1920

Pro Frame in die Texturen der Ebene rendern

const { session, gl, binding, projLayer } = await startXR();
const refSpace = await session.requestReferenceSpace('local');
const fb = gl.createFramebuffer();

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;

  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

  for (const view of pose.views) {
    const sub = binding.getViewSubImage(projLayer, view);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
      gl.TEXTURE_2D, sub.colorTexture, 0);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,
      gl.TEXTURE_2D, sub.depthStencilTexture, 0);

    const { x, y, width, height } = sub.viewport;
    gl.viewport(x, y, width, height);
    gl.clearColor(0.1, 0.1, 0.2, 1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    // drawScene(view.projectionMatrix, view.transform.inverse.matrix);
  }
};

session.requestAnimationFrame(onFrame);

Fallback bei fehlender Layers-Unterstützung und reduzierte Auflösung

const createMainLayer = (session, gl) => {
  if (typeof XRWebGLBinding !== 'undefined' &&
      'createProjectionLayer' in XRWebGLBinding.prototype) {
    try {
      const binding = new XRWebGLBinding(session, gl);
      const layer = binding.createProjectionLayer({ scaleFactor: 0.8 });
      session.updateRenderState({ layers: [layer] });
      return { type: 'projection', layer, binding };
    } catch (err) {
      console.warn('Projektionsebene nicht möglich:', err.name);
    }
  }
  // Klassischer Weg über XRWebGLLayer
  const baseLayer = new XRWebGLLayer(session, gl);
  session.updateRenderState({ baseLayer });
  return { type: 'webgl', layer: baseLayer };
};
Projektionsebene nicht möglich: NotSupportedError (nur ohne Layers-Feature)

// Wichtig · Fallstricke

  • Feature anfordern: Ohne "layers" in requiredFeatures oder optionalFeatures wirft die Methode einen NotSupportedError.
  • InvalidStateError tritt auf, wenn die Sitzung bereits beendet ist oder der WebGL-Kontext verloren ging.
  • textureType: "texture-array" funktioniert nur mit einem WebGL2-Kontext. Mit WebGL1 gibt es einen TypeError bzw. NotSupportedError.
  • Die Texturen gehören dem XR-System. Nutze sie nur innerhalb des aktuellen requestAnimationFrame-Callbacks und lösche sie nicht selbst. Frage sie jeden Frame neu mit getViewSubImage() ab, denn das System kann zwischen mehreren Texturen wechseln.
  • Pro Sitzung sollte es nur eine Projektionsebene geben. Setze sie nicht gleichzeitig mit baseLayer in updateRenderState(), sonst wird eine Ausnahme ausgelöst.
  • Kompatibilität: Die WebXR Layers API wird vor allem im Meta Quest Browser und in Chromium-basierten Browsern unterstützt, dort teilweise nur hinter einem Flag. Firefox und Safari unterstützen sie nicht. Prüfe die Unterstützung vorher (siehe Fallback-Beispiel). WebXR läuft außerdem nur in einem sicheren Kontext (HTTPS).