Start · Sprachen · JavaScript · Referenz · XREquirectLayer: redraw

XREquirectLayer: redraw

Ereignis

Wird an ein <code>XREquirectLayer</code> gesendet, wenn dessen Ressourcen verloren gehen oder der XR-Kompositor den Inhalt nicht mehr neu projizieren kann – der Inhalt muss neu gezeichnet werden.

seit JavaScript WebXR Layers API – experimentell, nur Chromium-bas Kategorie: webapi

Signatur

xrEquirectLayer.addEventListener("redraw", handler)

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

Typ
void
Beschreibung
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);
};
Inhalt verloren, zeichne neu: true

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;
redraw für XREquirectLayer

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 als optionalFeatures anfordern und bei fehlender Unterstützung auf XRWebGLLayer ausweichen.
  • Zeichnen Sie nicht direkt im Handler. getSubImage() braucht ein gültiges XRFrame, das es nur im requestAnimationFrame-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 nach redraw erneut 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.