Start · Sprachen · JavaScript · Referenz · XRCubeLayer: redraw

XRCubeLayer: redraw

Ereignis

Wird an ein <code>XRCubeLayer</code> gesendet, wenn seine Ressourcen verloren gehen oder der XR-Kompositor den Layer nicht mehr reprojizieren kann. Der Layer muss dann neu gezeichnet werden.

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

Signatur

xrCubeLayer.addEventListener("redraw", handler)

Beschreibung

Das Ereignis redraw gehört zur WebXR Layers API. Ein XRCubeLayer zeigt eine Cubemap an, also sechs quadratische Texturen, die den Betrachter umgeben. Typische Anwendungen sind Skyboxen und 360°-Umgebungen. Solche Layer werden meist einmalig gezeichnet, denn die Inhalte ändern sich selten. Den Rest übernimmt der Kompositor, der den Layer bei Kopfbewegungen selbstständig reprojiziert.

Es gibt aber Fälle, in denen der Inhalt des Layers ungültig wird. Das passiert, wenn die zugrunde liegenden GPU-Ressourcen verloren gehen, etwa nach einem Kontextverlust oder weil das System Speicher freigibt. Es passiert auch, wenn der Kompositor den Layer aus anderen Gründen nicht mehr reprojizieren kann. Dann feuert redraw. Parallel dazu wird die Eigenschaft XRCompositionLayer.needsRedraw auf true gesetzt. Die Anwendung sollte den Inhalt im nächsten XRFrame neu in die Texturen des Layers schreiben.

Einen Handler registrierst du entweder mit addEventListener("redraw", handler) oder über die Eigenschaft onredraw. Der Handler bekommt ein XRLayerEvent. Dessen Eigenschaft layer verweist auf den betroffenen Layer. Das Ereignis lässt sich nicht abbrechen und steigt nicht auf (kein Bubbling).

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname, hier immer "redraw".
$handler Pflicht (event: XRLayerEvent) => void Callback, der bei jedem Auftreten des Ereignisses aufgerufen wird. event.layer ist das betroffene XRCubeLayer.
$options boolean|AddEventListenerOptions false Optionale Listener-Optionen wie once, signal oder passive.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler bekommt ein XRLayerEvent.

Beispiele

Skybox nach Ressourcenverlust neu zeichnen (addEventListener)

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);

const cubeLayer = binding.createCubeLayer({
  space: refSpace,
  viewPixelWidth: 1024,
  viewPixelHeight: 1024
});
session.updateRenderState({ layers: [cubeLayer] });

let skyboxDirty = true; // beim ersten Frame zeichnen

cubeLayer.addEventListener('redraw', (event) => {
  console.log('Cube-Layer muss neu gezeichnet werden:', event.layer === cubeLayer);
  skyboxDirty = true;
});

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  if (skyboxDirty || cubeLayer.needsRedraw) {
    const subImage = binding.getSubImage(cubeLayer, frame);
    // drawSkyboxFaces ist deine eigene Funktion, die die sechs Seiten in subImage.colorTexture schreibt
    drawSkyboxFaces(gl, subImage.colorTexture);
    skyboxDirty = false;
  }
};
session.requestAnimationFrame(onFrame);
Cube-Layer muss neu gezeichnet werden: true

Handler über die onredraw-Eigenschaft setzen und wieder entfernen

const handleRedraw = (event) => {
  console.log('redraw für Layer', event.layer);
  needsSkyboxUpdate = true;
};

// Variante 1: on-Eigenschaft
cubeLayer.onredraw = handleRedraw;

// Handler entfernen
cubeLayer.onredraw = null;

// Variante 2: addEventListener / removeEventListener
cubeLayer.addEventListener('redraw', handleRedraw);
cubeLayer.removeEventListener('redraw', handleRedraw);

Listener beim Sitzungsende automatisch aufräumen (AbortController)

const controller = new AbortController();

cubeLayer.addEventListener('redraw', () => {
  pendingRedraw = true;
}, { signal: controller.signal });

session.addEventListener('end', () => {
  controller.abort(); // entfernt den redraw-Listener
  cubeLayer.destroy();
  console.log('Session beendet, Cube-Layer freigegeben');
});
Session beendet, Cube-Layer freigegeben

// Wichtig · Fallstricke

  • Kompatibilität: Die WebXR Layers API ist experimentell und wird derzeit praktisch nur von Chromium-basierten XR-Browsern unterstützt, etwa dem Meta Quest Browser. Firefox und Safari unterstützen sie nicht. Frage beim Start das Feature 'layers' an, das geht über requiredFeatures oder optionalFeatures. Prüfe vorher mit typeof XRCubeLayer !== 'undefined', ob die API vorhanden ist.
  • Cube-Layer sind nur in immersive-vr-Sitzungen erlaubt. In AR-Sitzungen wirft createCubeLayer() einen Fehler.
  • Zeichne nicht direkt im Event-Handler. Die Textur bekommst du erst über XRWebGLBinding.getSubImage(), und das geht nur innerhalb eines gültigen XRFrame-Callbacks. Setze im Handler deshalb nur ein Flag und zeichne im nächsten Frame.
  • Ergänzend kannst du in jedem Frame layer.needsRedraw prüfen. So verpasst du keine Neuzeichnung, auch wenn der Listener erst spät registriert wurde.
  • Statische Layer (isStatic: true) darf man nur einmal pro redraw beschreiben. Ohne Neuzeichnung bleibt der Layer nach einem Ressourcenverlust leer oder schwarz.