Start · Sprachen · JavaScript · Referenz · XRVisibilityMaskChangeEvent

XRVisibilityMaskChangeEvent

Schnittstelle

Ereignis der WebXR Device API, das beim Ändern der Sichtbarkeitsmaske einer <code>XRView</code> ausgelöst wird und die für den Benutzer sichtbare Fläche als Dreiecksnetz liefert.

seit JavaScript Experimentell – WebXR Device API; bisher nur in ei Kategorie: webapi

Signatur

interface XRVisibilityMaskChangeEvent extends Event

Beschreibung

XRVisibilityMaskChangeEvent ist das Ereignisobjekt zum Ereignis visibilitymaskchange, das auf einer XRSession ausgelöst wird. Es beschreibt, welcher Teil einer XRView für den Benutzer tatsächlich sichtbar ist. Bei vielen Headsets sieht man durch die Linsenoptik nur einen Teil des gerenderten Bildes, meistens einen abgerundeten Bereich. Die Ecken und Ränder werden also umsonst berechnet.

Das Ereignis liefert die sichtbare Fläche als Dreiecksnetz. vertices enthält die 2D-Eckpunkte als Paare aus x und y, indices die Dreiecksindizes. Mit eye und index ordnen Sie die Maske der passenden Ansicht zu. So können Sie die unsichtbaren Bereiche vor dem Rendern ausblenden, etwa mit einem Stencil- oder Tiefenpuffer-Durchlauf. Das spart Fragment-Shader-Arbeit und Füllrate, was auf mobilen Standalone-Headsets besonders viel bringt.

Das Ereignis wird normalerweise kurz nach dem Start der Sitzung ausgelöst und immer dann, wenn sich die Maske ändert, zum Beispiel wenn der Benutzer den Augenabstand oder die Linsen verstellt. Sie reagieren darauf mit session.addEventListener("visibilitymaskchange", handler) oder über die Eigenschaft session.onvisibilitymaskchange.

Eigenschaften (nur lesbar):

  • session: die XRSession, zu der die Maske gehört.
  • eye: das Auge ("left", "right" oder "none").
  • index: der Index der betroffenen Ansicht im views-Array der XRViewerPose.
  • vertices: ein Float32Array mit x/y-Koordinaten der Eckpunkte.
  • indices: ein Uint32Array mit Dreiecksindizes in vertices.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Name des Ereignisses. In der Praxis immer "visibilitymaskchange".
$options Pflicht Object Initialisierungsobjekt (XRVisibilityMaskChangeEventInit). Es erbt die Optionen von EventInit (bubbles, cancelable, composed).
$options.session Pflicht XRSession Die Sitzung, zu der die Maske gehört.
$options.eye Pflicht XREye Auge der Ansicht: "left", "right" oder "none".
$options.index Pflicht number Index der Ansicht im views-Array der Pose.
$options.vertices Pflicht Float32Array Eckpunkte des sichtbaren Bereichs als x/y-Paare.
$options.indices Pflicht Uint32Array Dreiecksindizes in vertices. Je drei Werte bilden ein Dreieck.

Rückgabewert

Typ
XRVisibilityMaskChangeEvent
Beschreibung
Ein neues Ereignisobjekt. Den Konstruktor brauchen Sie in der Regel nur für Tests oder Polyfills. Normalerweise erzeugt der Browser das Objekt.

Beispiele

Sichtbarkeitsmaske per addEventListener empfangen

const session = await navigator.xr.requestSession('immersive-vr');

// Masken pro Ansicht speichern
const masks = new Map();

session.addEventListener('visibilitymaskchange', (event) => {
  const { eye, index, vertices, indices } = event;
  masks.set(index, { eye, vertices, indices });
  console.log(`Maske für Auge "${eye}" (View ${index}): ` +
    `${vertices.length / 2} Eckpunkte, ${indices.length / 3} Dreiecke`);
});
Maske für Auge "left" (View 0): 64 Eckpunkte, 62 Dreiecke Maske für Auge "right" (View 1): 64 Eckpunkte, 62 Dreiecke

Maske in WebGL-Puffer laden (für einen Stencil-Durchlauf)

const gl = canvas.getContext('webgl2', { xrCompatible: true, stencil: true });
const maskBuffers = [];

session.onvisibilitymaskchange = (event) => {
  const entry = maskBuffers[event.index] ?? {
    vbo: gl.createBuffer(),
    ibo: gl.createBuffer()
  };

  gl.bindBuffer(gl.ARRAY_BUFFER, entry.vbo);
  gl.bufferData(gl.ARRAY_BUFFER, event.vertices, gl.STATIC_DRAW);

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, entry.ibo);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, event.indices, gl.STATIC_DRAW);

  entry.count = event.indices.length;
  maskBuffers[event.index] = entry;
};

// Später im Render-Loop pro View:
// Maske mit gl.drawElements(gl.TRIANGLES, entry.count, gl.UNSIGNED_INT, 0)
// in den Stencil-Puffer zeichnen, dann die Szene nur dort rendern,
// wo der Stencil-Wert gesetzt ist.

Feature-Erkennung und Handler wieder entfernen

const onMaskChange = (event) => {
  console.log('Neue Maske für View', event.index);
};

if ('XRVisibilityMaskChangeEvent' in window) {
  session.addEventListener('visibilitymaskchange', onMaskChange);
} else {
  console.log('Keine Sichtbarkeitsmasken – volles Bild wird gerendert.');
}

session.addEventListener('end', () => {
  session.removeEventListener('visibilitymaskchange', onMaskChange);
});
Neue Maske für View 0

// Wichtig · Fallstricke

  • Experimentell: Die Schnittstelle ist erst vor Kurzem in die WebXR-Spezifikation aufgenommen worden. Bisher gibt es sie nur in einzelnen Chromium-basierten XR-Browsern, etwa dem Meta Quest Browser. Firefox und Safari unterstützen sie derzeit nicht. Prüfen Sie deshalb immer mit 'XRVisibilityMaskChangeEvent' in window, ob sie verfügbar ist, und rendern Sie sonst ganz normal ohne Maske.
  • Es gibt keine Garantie, dass das Ereignis überhaupt ausgelöst wird. Ohne Maske müssen Sie die ganze Ansicht rendern.
  • Ordnen Sie die Masken über index zu und nicht nur über eye. Bei Geräten mit mehr als zwei Ansichten oder bei eye === "none" reicht das Auge allein nicht aus.
  • Die Maske kann sich während der Sitzung ändern. Aktualisieren Sie Ihre GPU-Puffer bei jedem Ereignis und nicht nur beim ersten.
  • Die Koordinaten beziehen sich auf die Projektion der jeweiligen Ansicht. Prüfen Sie beim Rendern, ob sie zu Ihrem Viewport bzw. zu Ihrer Projektionsmatrix passen.
  • Nur Sitzungen mit Headset-Optik (immersive-vr) liefern eine sinnvolle Maske. Bei inline-Sitzungen gibt es in der Regel keine.