Signatur
Beschreibung
Das Ereignis redraw gehört zur WebXR Layers API. Es wird an ein XREquirectLayer gesendet, also eine Ebene, die eine equirektangulare Textur (z. B. ein 360°-Panorama) auf eine Kugel um den Betrachter abbildet. Der XR-Kompositor löst es aus, wenn der Inhalt der Ebene nicht mehr gültig ist: Entweder sind die zugrunde liegenden GPU-Ressourcen verloren gegangen, oder der Kompositor kann die vorhandene Textur nicht mehr sinnvoll neu projizieren.
Das ist vor allem bei statischen Ebenen (erstellt mit isStatic: true) wichtig. Deren Inhalt zeichnet man in der Regel nur einmal und überlässt ihn dann dem Kompositor. Geht der Inhalt verloren, ist redraw das Signal, die Textur im nächsten requestAnimationFrame-Callback neu zu befüllen. Gleichzeitig wird die Eigenschaft needsRedraw der Ebene auf true gesetzt.
Einen Handler registriert man mit addEventListener("redraw", handler) oder über die Eigenschaft onredraw. Der Handler bekommt ein XRLayerEvent übergeben. Dessen Eigenschaft layer verweist auf die betroffene Ebene.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname, hier immer "redraw". |
|
| $handler Pflicht | (event: XRLayerEvent) => void | Callback, der ein XRLayerEvent erhält. event.layer ist das betroffene XREquirectLayer. |
|
| $options | boolean|AddEventListenerOptions | false | Optionale Listener-Optionen wie once, signal oder capture. |
Rückgabewert
addEventListener gibt nichts zurück. Das Ereignis selbst ist ein XRLayerEvent. Es ist nicht abbrechbar und steigt nicht auf (bubbles: false).Beispiele
Statisches 360°-Panorama bei redraw neu zeichnen
const startPanorama = async (canvas, image) => {
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 layer = binding.createEquirectLayer({
space: refSpace,
viewPixelWidth: image.width,
viewPixelHeight: image.height,
isStatic: true
});
session.updateRenderState({ layers: [layer] });
let pendingDraw = true; // erster Zeichenvorgang
layer.addEventListener('redraw', (event) => {
console.log('Inhalt verloren, zeichne neu:', event.layer === layer);
pendingDraw = true;
});
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
if (!pendingDraw && !layer.needsRedraw) return;
const sub = binding.getSubImage(layer, frame);
gl.bindTexture(gl.TEXTURE_2D, sub.colorTexture);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, image);
pendingDraw = false;
};
session.requestAnimationFrame(onFrame);
};
Handler über die onredraw-Eigenschaft setzen und entfernen
// layer ist ein bestehendes XREquirectLayer
layer.onredraw = (event) => {
console.log('redraw für', event.layer.constructor.name);
};
// Später wieder entfernen
layer.onredraw = null;
Listener mit AbortController beim Sitzungsende aufräumen
const controller = new AbortController();
const handleRedraw = () => {
console.log('Panorama muss neu gezeichnet werden');
};
layer.addEventListener('redraw', handleRedraw, { signal: controller.signal });
session.addEventListener('end', () => {
controller.abort(); // entfernt den redraw-Listener
// alternativ: layer.removeEventListener('redraw', handleRedraw);
}, { once: true });
// Wichtig · Fallstricke
- Experimentell: Die WebXR Layers API wird nur von wenigen Browsern unterstützt, vor allem vom Meta Quest Browser und von Chromium mit aktiviertem Flag. Firefox und Safari unterstützen sie nicht. Das Feature
'layers'sollte man alsoptionalFeaturesanfordern und bei fehlender Unterstützung aufXRWebGLLayerausweichen. - Zeichnen Sie nicht direkt im Handler.
getSubImage()braucht ein gültigesXRFrame, das es nur imrequestAnimationFrame-Callback gibt. Setzen Sie im Handler stattdessen nur ein Flag. - Bei statischen Ebenen (
isStatic: true) kann man pro Neuzeichnung nur einmal auf die Textur zugreifen. Den Bildinhalt (z. B.ImageBitmap) sollten Sie deshalb im Speicher behalten, um ihn nachredrawerneut hochladen zu können. - Das Ereignis kann schon kurz nach dem Erstellen der Ebene eintreffen. Prüfen Sie zusätzlich
layer.needsRedraw, damit kein Ereignis verpasst wird. - WebXR steht nur in sicheren Kontexten (HTTPS) zur Verfügung. Eingebettete Frames brauchen dafür die Permissions Policy
xr-spatial-tracking.