Signatur
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: dieXRSession, zu der die Maske gehört.eye: das Auge ("left","right"oder"none").index: der Index der betroffenen Ansicht imviews-Array derXRViewerPose.vertices: einFloat32Arraymit x/y-Koordinaten der Eckpunkte.indices: einUint32Arraymit Dreiecksindizes invertices.
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
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 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);
});
// 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
indexzu und nicht nur übereye. Bei Geräten mit mehr als zwei Ansichten oder beieye === "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. Beiinline-Sitzungen gibt es in der Regel keine.