Signatur
Beschreibung
Die Eigenschaft imageIndex eines XRWebGLSubImage gibt an, in welche Ebene (Layer) eines WebGL-2-Texturarrays (TEXTURE_2D_ARRAY) gerendert werden soll. Sie ist nur gesetzt, wenn der zugehörige Layer über XRWebGLBinding mit der Option textureType: "texture-array" erzeugt wurde. Dann teilen sich beide Augen eine einzige Array-Textur, und jedes Auge bekommt eine eigene Array-Ebene (typischerweise 0 für links und 1 für rechts).
Gebraucht wird der Wert jedes Frame. Nach dem Abruf des Sub-Images mit XRWebGLBinding.getViewSubImage() oder getSubImage() hängt man die Farbtextur mit gl.framebufferTextureLayer() an den Framebuffer an und übergibt imageIndex als Ebenen-Parameter. Wurde der Layer dagegen mit "texture" angelegt (Standard), ist imageIndex null. In dem Fall nutzt man gl.framebufferTexture2D() und viewport.
Texturarrays lassen sich gut mit der Multiview-Erweiterung OVR_multiview2 kombinieren. Damit rendert man beide Augen in einem einzigen Draw-Durchlauf, was auf mobilen VR-Headsets spürbar Leistung spart.
Rückgabewert
null, wenn der Layer nicht mit textureType: "texture-array" erzeugt wurde.Beispiele
Projektions-Layer mit Texturarray anlegen und imageIndex nutzen
const canvas = document.createElement('canvas');
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);
// Beide Augen teilen sich eine Array-Textur
const layer = binding.createProjectionLayer({ textureType: 'texture-array' });
session.updateRenderState({ layers: [layer] });
const fb = gl.createFramebuffer();
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
for (const view of pose.views) {
const sub = binding.getViewSubImage(layer, view);
// imageIndex wählt die Ebene im Array
gl.framebufferTextureLayer(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
sub.colorTexture, 0, sub.imageIndex
);
const { x, y, width, height } = sub.viewport;
gl.viewport(x, y, width, height);
gl.clearColor(0.1, 0.2, 0.3, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// ... Szene für dieses Auge zeichnen
}
};
session.requestAnimationFrame(onFrame);
Beide Textur-Typen robust behandeln
const attachSubImage = (gl, sub) => {
if (sub.imageIndex !== null) {
// Layer wurde mit 'texture-array' angelegt
gl.framebufferTextureLayer(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
sub.colorTexture, 0, sub.imageIndex
);
} else {
// Normale 2D-Textur
gl.framebufferTexture2D(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, sub.colorTexture, 0
);
}
};
Wert pro Auge protokollieren
const logIndices = (binding, layer, pose) => {
for (const view of pose.views) {
const sub = binding.getViewSubImage(layer, view);
console.log(view.eye, sub.imageIndex);
}
};
// Wichtig · Fallstricke
- Kompatibilität: Die WebXR Layers API ist experimentell. Unterstützt wird sie vor allem im Meta Quest Browser und in Chromium mit aktiviertem Feature-Flag. Firefox und Safari unterstützen sie nicht. Das Feature
'layers'muss inrequestSession()angefordert werden. Mittypeof XRWebGLBinding !== 'undefined'lässt sich vorab prüfen, ob die Schnittstelle überhaupt existiert. - Nur WebGL 2: Für
"texture-array"braucht es einenWebGL2RenderingContext. In einem WebGL-1-Kontext wirftcreateProjectionLayer()einen Fehler. - Auf
nullprüfen: Beinulldarf man den Wert nicht anframebufferTextureLayer()übergeben. Sonst wirdnullzu0umgewandelt, und die Textur ist falsch gebunden. - Nicht davon ausgehen, dass das linke Auge immer
0hat. Den Wert jedes Frame neu aus dem Sub-Image lesen. - Das Sub-Image und seine Texturen gelten nur innerhalb des aktuellen
XRFrame-Callbacks.