Signatur
Beschreibung
XRLayerEvent gehört zum Modul WebXR Layers der WebXR Device API. Das Interface erweitert Event um die schreibgeschützte Eigenschaft layer. Diese verweist auf die XRLayer, die das Ereignis ausgelöst hat. Wichtigster Anwendungsfall ist das Ereignis redraw. Es wird auf Kompositionsebenen (XRCompositionLayer) wie XRQuadLayer, XRCylinderLayer, XREquirectLayer oder XRCubeLayer ausgelöst.
Kompositionsebenen werden vom XR-Compositor unabhängig vom normalen Frame-Rendering dargestellt. Deshalb zeichnet man statische Inhalte wie Menüs, Texttafeln oder Skyboxen in der Regel nur einmal und nicht in jedem Frame. Das Laufzeitsystem kann den Inhalt der Textur aber verwerfen, etwa wenn die Sitzung pausiert oder der GPU-Kontext wiederhergestellt wird. Dann setzt es layer.needsRedraw auf true und löst redraw aus. Die Anwendung sollte daraufhin im nächsten requestAnimationFrame-Callback den Inhalt der Ebene neu zeichnen.
Einen Listener registrierst du entweder mit layer.addEventListener("redraw", handler) oder über die Eigenschaft layer.onredraw. Den Konstruktor new XRLayerEvent(type, eventInitDict) brauchst du nur selten, etwa für Tests oder selbst ausgelöste Ereignisse.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Name des Ereignisses, für Browser-Ereignisse immer "redraw". |
|
| $eventInitDict Pflicht | XRLayerEventInit | Objekt mit der Pflicht-Eigenschaft layer (die betroffene XRLayer) sowie optional bubbles, cancelable und composed aus EventInit. |
Rückgabewert
event.layer (nur lesbar) liefert die XRLayer, auf die sich das Ereignis bezieht.Beispiele
Quad-Ebene nur bei Bedarf neu zeichnen (addEventListener)
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const session = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['layers']
});
const refSpace = await session.requestReferenceSpace('local');
const binding = new XRWebGLBinding(session, gl);
const menuLayer = binding.createQuadLayer({
space: refSpace,
viewPixelWidth: 1024,
viewPixelHeight: 512,
layout: 'mono'
});
const projLayer = binding.createProjectionLayer();
session.updateRenderState({ layers: [projLayer, menuLayer] });
let menuDirty = true;
menuLayer.addEventListener('redraw', (event) => {
console.log('Neu zeichnen nötig für:', event.layer.constructor.name);
menuDirty = true;
});
const fb = gl.createFramebuffer();
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
if (menuDirty || menuLayer.needsRedraw) {
const sub = binding.getSubImage(menuLayer, frame);
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, sub.colorTexture, 0);
gl.viewport(sub.viewport.x, sub.viewport.y, sub.viewport.width, sub.viewport.height);
gl.clearColor(0.1, 0.2, 0.4, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
menuDirty = false;
}
};
session.requestAnimationFrame(onFrame);
Handler über onredraw setzen und wieder entfernen
// Annahme: cylinderLayer wurde per binding.createCylinderLayer() erzeugt
const handleRedraw = (event) => {
console.log('Zylinder-Ebene verloren – neu zeichnen');
scheduleRedraw(event.layer);
};
// Variante 1: Event-Handler-Eigenschaft
cylinderLayer.onredraw = handleRedraw;
// Variante 2: addEventListener / removeEventListener
cylinderLayer.addEventListener('redraw', handleRedraw);
// Beim Beenden der Sitzung aufräumen
session.addEventListener('end', () => {
cylinderLayer.onredraw = null;
cylinderLayer.removeEventListener('redraw', handleRedraw);
});
Synthetisches Ereignis für Tests erzeugen
// Annahme: quadLayer ist eine gültige XRQuadLayer
quadLayer.addEventListener('redraw', (e) => {
console.log(e instanceof XRLayerEvent, e.layer === quadLayer);
});
const testEvent = new XRLayerEvent('redraw', { layer: quadLayer });
quadLayer.dispatchEvent(testEvent);
// Wichtig · Fallstricke
Kompatibilität: Die WebXR Layers API ist experimentell und wird praktisch nur von Chromium-basierten XR-Browsern unterstützt, vor allem vom Meta Quest Browser. Desktop-Firefox und Safari bieten sie nicht an. Prüfe die Unterstützung per Feature-Erkennung ('XRLayerEvent' in window, 'XRWebGLBinding' in window). Fordere das Feature beim Start der Sitzung als requiredFeatures bzw. optionalFeatures: ['layers'] an.
- Zeichne im
redraw-Handler nicht direkt. Setze dort nur eine Markierung, denngetSubImage()braucht einen gültigenXRFrameund funktioniert nur imrequestAnimationFrame-Callback. - Zusätzlich zum Ereignis solltest du in jedem Frame
layer.needsRedrawprüfen. Direkt nach dem Erzeugen ist die Eigenschafttrue, ohne dassredrawausgelöst wird. XRProjectionLayerwird ohnehin in jedem Frame gezeichnet.redrawist vor allem bei Kompositionsebenen mit statischem Inhalt wichtig.- Das Ereignis ist nur in sicheren Kontexten (HTTPS) verfügbar, da WebXR selbst einen sicheren Kontext voraussetzt.