Start · Sprachen · JavaScript · Referenz · XRQuadLayer

XRQuadLayer

Schnittstelle

Kompositionsebene der WebXR Layers API, die einen flachen, rechteckigen Bereich im Raum zeigt, etwa für Text, Bedienoberflächen oder Videos.

seit JavaScript Experimentell: WebXR Layers API (u. a. Meta Quest Kategorie: webapi

Signatur

interface XRQuadLayer extends XRCompositionLayer

Beschreibung

XRQuadLayer gehört zur WebXR Layers API und beschreibt eine flache, rechteckige Fläche (ein „Quad“) im virtuellen Raum. Der XR-Kompositor des Geräts setzt die Ebene direkt zusammen. Die Inhalte laufen also nicht durch die normale WebGL-Projektion. Deshalb erscheinen Text, Menüs, Bilder und Videos auf solchen Ebenen deutlich schärfer und mit weniger Verzerrung, weil das Bild nur einmal abgetastet wird.

Du erzeugst eine Instanz nicht mit einem Konstruktor, sondern über XRWebGLBinding.prototype.createQuadLayer(init). Für Videoinhalte gibt es XRMediaBinding.prototype.createQuadLayer(video, init). Damit die Ebene sichtbar wird, trägst du sie über XRSession.updateRenderState({ layers: [...] }) in die Liste der Ebenen der Sitzung ein.

Wichtige Eigenschaften:

  • space (XRSpace): Referenzraum, in dem die Ebene verankert ist.
  • transform (XRRigidTransform): Position und Ausrichtung der Mitte der Ebene innerhalb von space.
  • width / height (number): Größe der Ebene in Metern.
  • Von XRCompositionLayer geerbt: layout, mipLevels, needsRedraw, blendTextureSourceAlpha, chromaticAberrationCorrection, quality und destroy().
  • Ereignis redraw: wird ausgelöst, wenn der Kompositor den Inhalt verloren hat und du ihn neu zeichnen musst.

Verwende XRQuadLayer für Inhalte, die im Raum stehen, aber flach bleiben sollen: virtuelle Monitore, HUD-Elemente, Untertitel oder Video-Leinwände. Für gekrümmte Flächen gibt es XRCylinderLayer, für Rundum-Hintergründe XREquirectLayer und XRCubeLayer.

Parameter

Name Typ Default Beschreibung
$init.space Pflicht XRSpace Referenzraum, in dem die Ebene positioniert wird, z. B. ein local-Raum.
$init.viewPixelWidth Pflicht number Breite der Farbtextur in Pixeln (nur bei XRWebGLBinding).
$init.viewPixelHeight Pflicht number Höhe der Farbtextur in Pixeln (nur bei XRWebGLBinding).
$init.transform XRRigidTransform Identität Position und Ausrichtung der Mitte der Ebene relativ zu space.
$init.width number 1.0 Breite der Ebene in Metern.
$init.height number 1.0 Höhe der Ebene in Metern.
$init.layout "default" | "mono" | "stereo" | "stereo-left-right" | "stereo-top-bottom" "mono" Legt fest, ob beide Augen dasselbe Bild sehen oder jedes Auge ein eigenes.
$init.textureType "texture" | "texture-array" "texture" Art der WebGL-Textur. texture-array erfordert WebGL2.
$init.colorFormat GLenum gl.RGBA Farbformat der Textur.
$init.depthFormat GLenum 0 (keine Tiefe) Optionales Format für den Tiefenpuffer.
$init.mipLevels number 1 Anzahl der Mipmap-Stufen.
$init.isStatic boolean false Bei true wird der Inhalt nur einmal gezeichnet und danach nur nach einem redraw-Ereignis. Das spart Rechenzeit bei statischen Inhalten.
$init.clearOnAccess boolean true Legt fest, ob die Textur bei jedem Zugriff geleert wird.

Rückgabewert

Typ
XRQuadLayer
Beschreibung
createQuadLayer() liefert eine neue XRQuadLayer-Instanz. Sie wird erst sichtbar, wenn du sie über updateRenderState({ layers }) in die Sitzung einträgst.

Beispiele

Sitzung mit Layers-Feature starten und Quad-Ebene erzeugen

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 refSpace = await session.requestReferenceSpace('local');
  const binding = new XRWebGLBinding(session, gl);

  // Quad 1,5 m breit, 1 m hoch, 2 m vor dem Betrachter
  const quadLayer = binding.createQuadLayer({
    space: refSpace,
    viewPixelWidth: 1536,
    viewPixelHeight: 1024,
    layout: 'mono',
    width: 1.5,
    height: 1.0,
    transform: new XRRigidTransform({ x: 0, y: 1.5, z: -2 })
  });

  // Projektionsebene für die 3D-Szene plus Quad darüber
  const projectionLayer = binding.createProjectionLayer();
  session.updateRenderState({ layers: [projectionLayer, quadLayer] });

  console.log(quadLayer.width, quadLayer.height);
  return { session, gl, binding, quadLayer, refSpace };
};
1.5 1

Inhalt in die Quad-Textur zeichnen (Render-Schleife)

const { session, gl, binding, quadLayer } = await startXR();
const fb = gl.createFramebuffer();

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);

  // Nur zeichnen, wenn nötig (z. B. beim ersten Frame oder nach redraw)
  if (!quadLayer.needsRedraw) return;

  const subImage = binding.getSubImage(quadLayer, frame);
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    gl.TEXTURE_2D, subImage.colorTexture, 0);

  const { x, y, width, height } = subImage.viewport;
  gl.viewport(x, y, width, height);
  gl.clearColor(0.1, 0.4, 0.8, 1.0); // blaue Tafel
  gl.clear(gl.COLOR_BUFFER_BIT);
};

session.requestAnimationFrame(onFrame);

Ebene verschieben, skalieren und auf redraw reagieren

// Virtuellen Monitor größer machen und nach rechts drehen
quadLayer.width = 2.4;
quadLayer.height = 1.35;
quadLayer.transform = new XRRigidTransform(
  { x: 0.5, y: 1.6, z: -2.5 },
  { x: 0, y: -0.259, z: 0, w: 0.966 } // ca. 30° um die Y-Achse
);

quadLayer.addEventListener('redraw', () => {
  console.log('Kompositor verlangt ein Neuzeichnen');
});

// Aufräumen beim Beenden
session.addEventListener('end', () => quadLayer.destroy());
Kompositor verlangt ein Neuzeichnen

Video als Quad-Ebene über XRMediaBinding

const video = document.querySelector('video');
const mediaBinding = new XRMediaBinding(session);

const videoLayer = mediaBinding.createQuadLayer(video, {
  space: refSpace,
  layout: 'mono',
  transform: new XRRigidTransform({ x: 0, y: 1.6, z: -3 })
});

session.updateRenderState({ layers: [projectionLayer, videoLayer] });
await video.play();