Start · Sprachen · JavaScript · Referenz · XRLayerEvent.layer

XRLayerEvent.layer

Eigenschaft

Die schreibgeschützte Eigenschaft <code>layer</code> von <code>XRLayerEvent</code> verweist auf die <code>XRLayer</code>-Instanz, die das Ereignis ausgelöst hat.

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

Signatur

XRLayerEvent.layer

Beschreibung

Die Eigenschaft XRLayerEvent.layer ist schreibgeschützt. Sie liefert die Ebene (XRLayer), von der ein Ereignis der WebXR Layers API stammt. Praktisch betrifft das vor allem das redraw-Ereignis. Kompositionsebenen wie XRQuadLayer, XRCylinderLayer, XREquirectLayer und XRCubeLayer lösen es aus, wenn der Browser ihren Inhalt verworfen hat und die Anwendung ihn neu zeichnen muss.

Nützlich ist die Eigenschaft vor allem, wenn ein einziger Ereignis-Handler für mehrere Ebenen zuständig ist. Das ist zum Beispiel der Fall bei mehreren schwebenden UI-Panels als Quad-Ebenen. Über event.layer erkennt der Handler, welche Ebene neu gezeichnet werden muss. Er braucht dafür keine eigene Closure pro Ebene.

Wichtig: Das redraw-Ereignis ist nur ein Signal. Gezeichnet wird nicht im Ereignis-Handler. Das geschieht erst im nächsten Rückruf von XRSession.requestAnimationFrame(), denn nur dort gibt es ein gültiges XRFrame. Mit diesem Frame holt man über XRWebGLBinding.getSubImage() die Zieltextur. Üblich ist deshalb folgendes Vorgehen: Im Handler wird die Ebene aus event.layer vorgemerkt, und im Frame-Rückruf wird sie dann neu gerendert.

Rückgabewert

Typ
XRLayer
Beschreibung
Die Ebene, die das Ereignis ausgelöst hat. In der Praxis ist das meist eine Unterklasse von XRCompositionLayer, etwa XRQuadLayer oder XRCylinderLayer. Der Wert wird beim Erzeugen des Ereignisses festgelegt und lässt sich danach nicht mehr ändern.

Beispiele

redraw-Ereignis mit addEventListener und event.layer auswerten

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

const session = await navigator.xr.requestSession('immersive-vr', {
  requiredFeatures: ['layers']
});
const binding = new XRWebGLBinding(session, gl);
const refSpace = await session.requestReferenceSpace('local');

const menuLayer = binding.createQuadLayer({
  space: refSpace,
  viewPixelWidth: 1024,
  viewPixelHeight: 512,
  layout: 'mono',
  width: 1.0,
  height: 0.5
});

const projectionLayer = binding.createProjectionLayer();
session.updateRenderState({ layers: [projectionLayer, menuLayer] });

menuLayer.addEventListener('redraw', (event) => {
  // event.layer ist dieselbe Instanz wie menuLayer
  console.log(event.layer === menuLayer);
  console.log(event.layer.needsRedraw);
});
true true

Ein Handler für mehrere Ebenen: Neuzeichnen im nächsten Frame

// Voraussetzung: session, binding und refSpace wie im ersten Beispiel
const panels = ['links', 'rechts'].map((name, i) => {
  const layer = binding.createQuadLayer({
    space: refSpace,
    viewPixelWidth: 512,
    viewPixelHeight: 512,
    layout: 'mono',
    transform: new XRRigidTransform({ x: i === 0 ? -0.8 : 0.8, y: 1.5, z: -2 })
  });
  layer.name = name; // eigene Markierung
  return layer;
});

const dirty = new Set();

const onRedraw = (event) => {
  // Nur vormerken, nicht hier zeichnen
  dirty.add(event.layer);
  console.log(`Panel "${event.layer.name}" muss neu gezeichnet werden`);
};

panels.forEach((layer) => layer.addEventListener('redraw', onRedraw));

const onFrame = (time, frame) => {
  for (const layer of dirty) {
    const sub = binding.getSubImage(layer, frame);
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
      gl.TEXTURE_2D, sub.colorTexture, 0);
    drawPanel(layer.name); // eigene Render-Funktion
  }
  dirty.clear();
  frame.session.requestAnimationFrame(onFrame);
};
session.requestAnimationFrame(onFrame);
Panel "links" muss neu gezeichnet werden

Alternative über die onredraw-Eigenschaft

// Nur ein Handler pro Ebene möglich – eine neue Zuweisung ersetzt den alten
menuLayer.onredraw = ({ layer }) => {
  console.log(layer.constructor.name);
  needsMenuRedraw = true;
};

// Handler wieder entfernen
menuLayer.onredraw = null;
XRQuadLayer

// Wichtig · Fallstricke

  • Experimentell: Die WebXR Layers API ist noch nicht in allen Browsern verfügbar. Am besten unterstützt wird sie derzeit im Meta Quest Browser. Desktop-Firefox und Safari unterstützen sie nicht. Damit Ebenen überhaupt entstehen, muss die Sitzung mit requiredFeatures oder optionalFeatures: ['layers'] angefordert werden. Außerdem ist ein sicherer Kontext (HTTPS) nötig.
  • Nicht im Handler zeichnen: getSubImage() braucht ein gültiges XRFrame. Im redraw-Handler gibt es keins. Merken Sie sich event.layer deshalb vor und zeichnen Sie die Ebene im nächsten requestAnimationFrame-Rückruf.
  • Schreibgeschützt: Eine Zuweisung an event.layer wird im nicht-strikten Modus stillschweigend ignoriert und löst im strikten Modus einen TypeError aus.
  • Der Konstruktor new XRLayerEvent(type, { layer }) verlangt eine echte XRLayer-Instanz. Für Unit-Tests ohne XR-Gerät müssen Sie deshalb Mocks oder den WebXR-Emulator verwenden.
  • Referenzen auf Ebenen aus beendeten Sitzungen sollten Sie verwerfen, zum Beispiel in einem Set vorgemerkter Ebenen. Andernfalls entstehen Speicherlecks. Nach XRSession.end() oder layer.destroy() ist die Ebene nicht mehr verwendbar.