Signatur
Beschreibung
Die Methode createCylinderLayer() einer XRMediaBinding-Instanz erzeugt eine Medien-Schicht in Form eines Zylinderausschnitts. Der Inhalt eines <video>-Elements wird dabei direkt vom Compositor des XR-Geräts auf die gekrümmte Fläche gezeichnet. Sie müssen die Videobilder also nicht selbst in einer WebGL-Renderschleife als Textur hochladen.
Zylinder-Schichten eignen sich besonders für Kino- und Panorama-Leinwände, die den Nutzer halb umschließen. Bei gleicher Breite verzerren sie am Rand weniger als eine flache Quad-Schicht. Weil der Compositor direkt zeichnet, sind Text und Video meist schärfer und der Energieverbrauch ist geringer als beim Rendern über eine Projektionsschicht.
Die Form wird über radius, centralAngle (Bogenwinkel im Bogenmaß) und aspectRatio bestimmt, die Lage über space und transform. Mit layout lassen sich auch Stereo-Videos (nebeneinander oder übereinander) korrekt auf beide Augen verteilen. Die erzeugte Schicht wird erst sichtbar, wenn Sie sie über XRSession.updateRenderState({ layers: [...] }) in die Schichtliste der Sitzung aufnehmen.
Voraussetzung ist eine immersive Sitzung, die mit dem Feature "layers" angefordert wurde. Die Sitzung wird beim Konstruktor new XRMediaBinding(session) übergeben.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $video Pflicht | HTMLVideoElement | Das Videoelement, dessen Bilder auf der Schicht angezeigt werden. | |
| $options Pflicht | Object | Konfigurationsobjekt mit den folgenden Eigenschaften. | |
| $options.space Pflicht | XRSpace | Referenzraum, in dem die Schicht positioniert wird, z. B. aus session.requestReferenceSpace("local"). |
|
| $options.layout | "mono" | "stereo-left-right" | "stereo-top-bottom" | "mono" | Aufteilung des Videobilds auf die Augen. Bei Stereo-Layouts erhält jedes Auge die passende Hälfte des Bilds. |
| $options.invertStereo | boolean | false | Vertauscht bei Stereo-Layouts linke und rechte Bildhälfte. |
| $options.transform | XRRigidTransform | Identitätstransformation | Position und Ausrichtung des Zylindermittelpunkts relativ zu space. |
| $options.radius | number | 2.0 | Radius des Zylinders in Metern, also der Abstand der Leinwand vom Mittelpunkt. |
| $options.centralAngle | number | 0.78539 (π/4) | Horizontaler Bogenwinkel des sichtbaren Zylinderausschnitts im Bogenmaß. |
| $options.aspectRatio | number | Seitenverhältnis des Videos | Verhältnis von Breite zu Höhe der Schicht. Ohne Angabe wird es aus videoWidth/videoHeight bzw. dem Layout abgeleitet. |
Rückgabewert
radius, centralAngle, aspectRatio und transform lassen sich später noch ändern.Beispiele
Video als gekrümmte Kinoleinwand anzeigen
const startCinema = async () => {
const video = document.querySelector('#film');
const session = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['layers']
});
const refSpace = await session.requestReferenceSpace('local');
const mediaBinding = new XRMediaBinding(session);
const cylinderLayer = mediaBinding.createCylinderLayer(video, {
space: refSpace,
radius: 3, // 3 m entfernt
centralAngle: Math.PI / 2, // 90° Bogen
transform: new XRRigidTransform({ x: 0, y: 1.6, z: 0 })
});
session.updateRenderState({ layers: [cylinderLayer] });
await video.play();
};
document.querySelector('#start').addEventListener('click', startCinema);
Stereo-Video (nebeneinander) mit Projektionsschicht kombinieren
const setupStereoScreen = async (session, gl, video) => {
const refSpace = await session.requestReferenceSpace('local-floor');
const glBinding = new XRWebGLBinding(session, gl);
const projectionLayer = glBinding.createProjectionLayer();
const mediaBinding = new XRMediaBinding(session);
const screen = mediaBinding.createCylinderLayer(video, {
space: refSpace,
layout: 'stereo-left-right',
radius: 4,
centralAngle: Math.PI / 3,
transform: new XRRigidTransform({ x: 0, y: 1.5, z: -1 })
});
// Reihenfolge: hintere Schichten zuerst
session.updateRenderState({ layers: [projectionLayer, screen] });
return screen;
};
Leinwand zur Laufzeit vergrößern und Feature-Erkennung
if (!('XRMediaBinding' in window)) {
console.warn('WebXR-Medienschichten werden nicht unterstützt.');
}
// screen ist ein zuvor erzeugter XRCylinderLayer
const widenScreen = (screen) => {
screen.centralAngle = Math.min(screen.centralAngle * 1.25, Math.PI);
console.log(`Neuer Bogen: ${(screen.centralAngle * 180 / Math.PI).toFixed(0)}°`);
};
// Wichtig · Fallstricke
- Experimentell: Die WebXR Layers API wird bisher nur von einigen Chromium-basierten Browsern unterstützt, vor allem vom Meta Quest Browser. Firefox und Safari unterstützen sie nicht. Prüfen Sie deshalb immer vorab mit
'XRMediaBinding' in window. - Die Sitzung muss mit
requiredFeaturesoderoptionalFeatures: ['layers']angefordert werden. Wurde"layers"nicht aktiviert oder ist die Sitzung bereits beendet, wirft die Methode eineInvalidStateError-DOMException. - Die Schicht wird erst nach
session.updateRenderState({ layers })sichtbar. In der Schichtliste stehen hintere Schichten zuerst. - Das Video muss selbst abgespielt werden (
video.play()). Wegen der Autoplay-Richtlinien sollte der Aufruf in einer Nutzerinteraktion erfolgen. Videos von fremden Ursprüngen benötigen CORS (crossorigin-Attribut). centralAnglewird im Bogenmaß angegeben, nicht in Grad. Sehr große Winkel nahe2πerzeugen einen fast geschlossenen Ring.- Kennt der Browser die Videoabmessungen noch nicht (vor
loadedmetadata), kann das automatisch abgeleiteteaspectRatiofalsch sein. Geben Sie es im Zweifel ausdrücklich an.