Start · Sprachen · JavaScript · Referenz · XRMediaBinding

XRMediaBinding

Schnittstelle

Erzeugt WebXR-Kompositionsebenen (Quad, Zylinder, Equirect), die den Inhalt eines <code>HTMLVideoElement</code> direkt in einer immersiven XR-Sitzung anzeigen.

seit JavaScript Experimentell (WebXR Layers API) – u. a. Meta Ques Kategorie: webapi

Signatur

interface XRMediaBinding

Beschreibung

XRMediaBinding gehört zur WebXR Layers API. Damit lassen sich Videos als eigene Ebenen (Layers) in einer immersiven Sitzung anzeigen. Der XR-Kompositor des Geräts rendert das Video selbst. Die Anwendung muss keine Videoframes per WebGL in eine Textur kopieren. Das spart Rechenzeit und Akku, und die Darstellung ist schärfer, weil nur einmal neu abgetastet wird.

Ein XRMediaBinding wird mit new XRMediaBinding(session) an eine laufende XRSession gebunden. Es bietet drei Fabrikmethoden:

  • createQuadLayer(video, init): flache, rechteckige Fläche im Raum, zum Beispiel eine virtuelle Leinwand.
  • createCylinderLayer(video, init): gekrümmte Fläche, ein Ausschnitt eines Zylindermantels.
  • createEquirectLayer(video, init): Kugelprojektion für 180°- und 360°-Videos.

Die erzeugten Ebenen (XRQuadLayer, XRCylinderLayer, XREquirectLayer) werden über session.updateRenderState({ layers: [...] }) aktiviert. Die Reihenfolge im Array bestimmt, welche Ebene über welcher liegt. Stereo-Videos (nebeneinander oder übereinander) werden über die Option layout richtig auf beide Augen verteilt.

Voraussetzung ist eine Sitzung, die mit dem Feature "layers" angefordert wurde. Das Video selbst steuerst du wie gewohnt über das HTMLVideoElement (play(), pause(), currentTime).

Parameter

Name Typ Default Beschreibung
$session Pflicht XRSession Konstruktor-Argument: die immersive Sitzung, an die die Medienebenen gebunden werden. Die Sitzung muss mit requiredFeatures oder optionalFeatures ["layers"] angefordert worden sein.
$video Pflicht HTMLVideoElement Argument der create*Layer()-Methoden: das Videoelement, dessen Inhalt angezeigt wird.
$init.space Pflicht XRSpace Referenzraum, in dem die Ebene positioniert wird, z. B. aus session.requestReferenceSpace("local").
$init.layout "mono" | "stereo-left-right" | "stereo-top-bottom" "mono" Aufteilung des Videobildes auf die Augen. Für Side-by-Side- bzw. Over-Under-3D-Videos entsprechend setzen.
$init.invertStereo boolean false Vertauscht linkes und rechtes Auge bei Stereo-Layouts.
$init.transform XRRigidTransform Identität Position und Ausrichtung der Ebene relativ zu space.
$init.width / init.height number Seitenverhältnis des Videos Nur createQuadLayer(): Größe der Fläche in Metern. Wird nur ein Wert angegeben, ergibt sich der andere aus dem Seitenverhältnis des Videos.
$init.radius / init.centralAngle / init.aspectRatio number radius 2, centralAngle 0.78539 (π/4) Nur createCylinderLayer(): Radius in Metern, horizontaler Öffnungswinkel im Bogenmaß und Seitenverhältnis.
$init.radius / init.centralHorizontalAngle / init.upperVerticalAngle / init.lowerVerticalAngle number radius 0 (unendlich), 2π, π/2, −π/2 Nur createEquirectLayer(): Kugelradius (0 = unendlich weit entfernt) und Winkelbereiche im Bogenmaß. Für 180°-Videos centralHorizontalAngle: Math.PI setzen.

Rückgabewert

Typ
XRMediaBinding
Beschreibung
Der Konstruktor liefert ein XRMediaBinding-Objekt. Dessen Methoden geben jeweils XRQuadLayer, XRCylinderLayer oder XREquirectLayer zurück.

Beispiele

Video als virtuelle Leinwand (Quad-Ebene)

const video = document.querySelector('video');

const startXR = async () => {
  const session = await navigator.xr.requestSession('immersive-vr', {
    requiredFeatures: ['layers']
  });
  const space = await session.requestReferenceSpace('local');

  const mediaBinding = new XRMediaBinding(session);
  const quadLayer = mediaBinding.createQuadLayer(video, {
    space,
    width: 3, // 3 Meter breit, die Höhe folgt aus dem Seitenverhältnis
    transform: new XRRigidTransform({ x: 0, y: 1.5, z: -3 })
  });

  session.updateRenderState({ layers: [quadLayer] });
  await video.play();
  console.log('Leinwand aktiv:', quadLayer.width, 'x', quadLayer.height);
};

// Muss durch eine Benutzeraktion ausgelöst werden
document.querySelector('#enter-vr').addEventListener('click', startXR);
Leinwand aktiv: 3 x 1.6875

360°-Stereo-Video mit Equirect-Ebene

const play360 = async (video) => {
  const session = await navigator.xr.requestSession('immersive-vr', {
    requiredFeatures: ['layers']
  });
  const space = await session.requestReferenceSpace('local');
  const binding = new XRMediaBinding(session);

  const sphere = binding.createEquirectLayer(video, {
    space,
    layout: 'stereo-top-bottom', // oberes Bild = linkes Auge
    centralHorizontalAngle: Math.PI * 2,
    upperVerticalAngle: Math.PI / 2,
    lowerVerticalAngle: -Math.PI / 2
  });

  session.updateRenderState({ layers: [sphere] });
  await video.play();

  session.addEventListener('end', () => video.pause());
};

document.querySelector('#start').addEventListener('click', () => {
  play360(document.querySelector('#pano'));
});

Gekrümmte Leinwand plus WebGL-Szene mit Fallback

const setupLayers = async (session, gl, video) => {
  const space = await session.requestReferenceSpace('local-floor');

  if (typeof XRMediaBinding === 'undefined') {
    console.warn('XRMediaBinding wird nicht unterstützt – das Video muss per WebGL-Textur gerendert werden.');
    return;
  }

  const glBinding = new XRWebGLBinding(session, gl);
  const projection = glBinding.createProjectionLayer();

  const mediaBinding = new XRMediaBinding(session);
  const cylinder = mediaBinding.createCylinderLayer(video, {
    space,
    radius: 4,
    centralAngle: Math.PI / 2,
    aspectRatio: 16 / 9,
    transform: new XRRigidTransform({ y: 1.6 })
  });

  // Reihenfolge: zuerst die Szene, das Video liegt darüber
  session.updateRenderState({ layers: [projection, cylinder] });
};