Signatur
Beschreibung
Die schreibgeschützte Eigenschaft indices des Interfaces XRVisibilityMaskChangeEvent enthält ein Uint32Array. Je drei aufeinanderfolgende Werte beschreiben ein Dreieck. Alle Dreiecke zusammen bilden die Sichtbarkeitsmaske: den Bereich einer Ansicht (XRView), den der Nutzer auf dem Display des Headsets tatsächlich sieht.
Wichtig: Ein Index zeigt nicht direkt auf einen einzelnen Eintrag im Array vertices. Er zeigt auf ein Koordinatenpaar. Der Index i steht also für den Punkt (vertices[2 * i], vertices[2 * i + 1]). Die Koordinaten liegen im normalisierten Projektionsraum der jeweiligen Ansicht.
Das Ereignis visibilitymaskchange wird auf der XRSession ausgelöst. Das geschieht beim Start der Sitzung und immer dann, wenn sich die Maske einer Ansicht ändert. Die Maske wird vor allem zur Leistungsoptimierung verwendet: Man zeichnet sie zum Beispiel in den Stencil- oder Tiefenpuffer. So werden Pixel, die durch die Linsen ohnehin nicht zu sehen sind, gar nicht erst berechnet. Ist indices leer, gibt es für diese Ansicht keine Einschränkung und die ganze Fläche ist sichtbar.
Rückgabewert
vertices. Ein leeres Array bedeutet: keine Maske, die ganze Fläche ist sichtbar.Beispiele
Auf Maskenänderungen reagieren
const session = await navigator.xr.requestSession('immersive-vr');
session.addEventListener('visibilitymaskchange', (event) => {
const { index, indices, vertices } = event;
console.log(`Ansicht ${index}: ${indices.length / 3} Dreiecke, ${vertices.length / 2} Eckpunkte`);
});
Dreiecke aus indices und vertices auflösen
const getTriangles = ({ indices, vertices }) => {
const point = (i) => [vertices[2 * i], vertices[2 * i + 1]];
const triangles = [];
for (let t = 0; t < indices.length; t += 3) {
triangles.push([point(indices[t]), point(indices[t + 1]), point(indices[t + 2])]);
}
return triangles;
};
session.onvisibilitymaskchange = (event) => {
const triangles = getTriangles(event);
console.log('Erstes Dreieck:', triangles[0]);
};
Maske als WebGL-Indexpuffer für den Stencil-Pass hochladen
const masks = new Map();
session.addEventListener('visibilitymaskchange', ({ index, vertices, indices }) => {
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
masks.set(index, { vbo, ibo, count: indices.length });
});
// Später im Render-Loop je Ansicht:
// gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
// gl.drawElements(gl.TRIANGLES, mask.count, gl.UNSIGNED_INT, 0);
// Wichtig · Fallstricke
- Indizes zeigen auf Paare: Ein Index zeigt auf ein Koordinatenpaar, nicht auf einen einzelnen Array-Eintrag. In WebGL muss die Stride deshalb 2 Floats betragen (
vertexAttribPointer(loc, 2, …)). Wer den Index direkt inverticesnachschlägt, bekommt falsche Punkte. - 32-Bit-Indizes:
drawElementsmitgl.UNSIGNED_INTfunktioniert in WebGL 1 nur mit der ErweiterungOES_element_index_uint. In WebGL 2 ist das ohne Erweiterung möglich. - Leeres Array: Ist das Array leer, gibt es keine Maske. Diesen Fall abfangen und dann auf den Stencil-Pass verzichten.
- Kompatibilität: Die Eigenschaft ist experimentell und nur in wenigen Chromium-basierten XR-Browsern verfügbar. Vorher prüfen, z. B. mit
'XRVisibilityMaskChangeEvent' in window. WebXR funktioniert nur in sicheren Kontexten (HTTPS). - Das Ereignis kann während einer Sitzung mehrfach kommen. Alte Puffer dann mit
gl.deleteBuffer()freigeben.