Signatur
Beschreibung
Die Methode createCubeLayer() der Schnittstelle XRWebGLBinding erzeugt ein XRCubeLayer. Diese Ebene nimmt eine Cubemap-Textur (TEXTURE_CUBE_MAP) mit sechs Flächen entgegen und stellt sie auf den Innenseiten eines unendlich großen, um den Betrachter zentrierten Würfels dar. Der Compositor des XR-Geräts übernimmt die Darstellung selbst, sodass die Umgebung auch bei niedriger Bildrate der Anwendung scharf und ruckelfrei bleibt.
Typische Anwendungsfälle sind Skyboxen, statische 360°-Panoramen und Hintergrundumgebungen, die sich nicht mit der Kopfposition, sondern nur mit der Blickrichtung verändern. Die Position des Betrachters innerhalb des Würfels spielt keine Rolle – nur die Orientierung (orientation) und der Referenzraum (space) bestimmen die Ausrichtung.
Nach dem Erstellen muss die Ebene über XRSession.updateRenderState({ layers: [...] }) in die Ebenenliste aufgenommen werden. Zum Befüllen holt man sich pro Frame mit XRWebGLBinding.getSubImage(layer, frame) ein XRWebGLSubImage, dessen colorTexture eine Cubemap ist, und rendert in jede der sechs Flächen. Bei isStatic: true darf nur nach dem Erstellen bzw. nach einem redraw-Ereignis gezeichnet werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $init Pflicht | XRCubeLayerInit | Konfigurationsobjekt mit den folgenden Eigenschaften:
|
Rückgabewert
XRCubeLayer-Objekt, das anschließend in XRRenderState.layers eingetragen werden muss, um sichtbar zu werden.Beispiele
Session mit Layers-Feature starten und Skybox-Ebene anlegen
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);
const skyLayer = binding.createCubeLayer({
space: refSpace,
viewPixelWidth: 1024,
viewPixelHeight: 1024,
layout: 'mono',
isStatic: true
});
// Projektionsebene für die eigentliche Szene davor legen
const projLayer = binding.createProjectionLayer({ textureType: 'texture' });
session.updateRenderState({ layers: [skyLayer, projLayer] });
console.log(skyLayer.layout);
Sechs Cubemap-Flächen aus Bildern befüllen
// faces: Array aus 6 geladenen ImageBitmaps (+X, -X, +Y, -Y, +Z, -Z)
const drawSkybox = (frame, faces) => {
if (!skyLayer.needsRedraw) return;
const subImage = binding.getSubImage(skyLayer, frame);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, subImage.colorTexture);
faces.forEach((bitmap, i) => {
gl.texSubImage2D(
gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, 0, 0,
gl.RGBA, gl.UNSIGNED_BYTE,
bitmap
);
});
gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
};
session.requestAnimationFrame(function onFrame(time, frame) {
drawSkybox(frame, faces);
frame.session.requestAnimationFrame(onFrame);
});
Würfel drehen und auf redraw reagieren
// Um 90° um die Y-Achse drehen (Quaternion)
const s = Math.sin(Math.PI / 4);
skyLayer.orientation = new DOMPointReadOnly(0, s, 0, Math.cos(Math.PI / 4));
// Statische Ebenen können vom System geleert werden
skyLayer.addEventListener('redraw', () => {
console.log('Skybox muss neu gezeichnet werden');
});