Start · Sprachen · JavaScript · Referenz · XRLightProbe

XRLightProbe

Schnittstelle

Stellt in einer WebXR-AR-Sitzung eine Lichtsonde dar, die Beleuchtungsinformationen (Lichtschätzung, Reflexions-Cubemap) der realen Umgebung liefert.

seit JavaScript Experimentell: Chrome/Edge 90+ (Android, ARCore), Kategorie: webapi

Signatur

interface XRLightProbe extends EventTarget

Beschreibung

XRLightProbe gehört zum Modul WebXR Lighting Estimation der WebXR Device API. Ein solches Objekt misst die Beleuchtung der realen Umgebung und ermöglicht so, dass virtuelle Objekte in Augmented Reality glaubwürdig beleuchtet werden – mit passender Lichtrichtung, Intensität, Farbe und Umgebungsreflexionen.

Du erzeugst die Schnittstelle nicht direkt mit einem Konstruktor, sondern über XRSession.requestLightProbe(options). Das geht nur in einer immersive-ar-Sitzung, die mit dem Feature "light-estimation" angefordert wurde. Mit der Sonde fragst du dann in jedem Frame per XRFrame.getLightEstimate(lightProbe) ein XRLightEstimate ab (sphärische Harmonische, Richtung und Intensität der Hauptlichtquelle). Über XRWebGLBinding.getReflectionCubeMap(lightProbe) erhältst du eine Cubemap-Textur für spiegelnde Reflexionen.

Mitglieder der Schnittstelle:

  • probeSpace (nur lesbar, XRSpace): Koordinatenraum, dessen Ausrichtung zu den Lichtdaten gehört. Mit frame.getPose(probeSpace, refSpace) rechnest du die Lichtrichtung in deinen Referenzraum um.
  • reflectionchange-Event bzw. onreflectionchange: wird ausgelöst, wenn das System eine neue Reflexions-Cubemap berechnet hat. Das ist der richtige Moment, um getReflectionCubeMap() erneut aufzurufen.

Parameter

Name Typ Default Beschreibung
$options XRLightProbeInit {} Optionen für XRSession.requestLightProbe(), mit dem eine XRLightProbe erzeugt wird.
$options.reflectionFormat "srgba8" | "rgba16f" "srgba8" Gewünschtes Texturformat der Reflexions-Cubemap. "rgba16f" (HDR) ist nur erlaubt, wenn session.preferredReflectionFormat es meldet, sonst wird das Promise abgelehnt.

Rückgabewert

Typ
Promise<XRLightProbe>
Beschreibung
XRSession.requestLightProbe() gibt ein Promise zurück, das mit der XRLightProbe erfüllt wird. Ist "light-estimation" nicht aktiviert, wird es mit einer NotSupportedError-DOMException abgelehnt.

Beispiele

Lichtsonde anfordern und Hauptlicht pro Frame auslesen

const session = await navigator.xr.requestSession('immersive-ar', {
  requiredFeatures: ['light-estimation']
});
const refSpace = await session.requestReferenceSpace('local');
const lightProbe = await session.requestLightProbe();

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);

  const estimate = frame.getLightEstimate(lightProbe);
  if (!estimate) return; // noch keine Daten verfügbar

  const { x, y, z } = estimate.primaryLightDirection;
  const { x: r, y: g, z: b } = estimate.primaryLightIntensity;
  console.log(`Licht aus Richtung (${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)}), RGB ${r.toFixed(2)}/${g.toFixed(2)}/${b.toFixed(2)}`);
  // hier z. B. die DirectionalLight-Werte der 3D-Engine aktualisieren
};
session.requestAnimationFrame(onFrame);
Licht aus Richtung (0.12, 0.95, -0.28), RGB 1.43/1.38/1.21

Lichtrichtung mit probeSpace in den Referenzraum umrechnen

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  const estimate = frame.getLightEstimate(lightProbe);
  const probePose = frame.getPose(lightProbe.probeSpace, refSpace);
  if (!estimate || !probePose) return;

  // Richtung als Vektor (w = 0) mit der Pose-Matrix transformieren
  const m = probePose.transform.matrix;
  const d = estimate.primaryLightDirection;
  const world = [
    m[0] * d.x + m[4] * d.y + m[8] * d.z,
    m[1] * d.x + m[5] * d.y + m[9] * d.z,
    m[2] * d.x + m[6] * d.y + m[10] * d.z
  ];
  console.log('Lichtrichtung im local-Raum:', world.map(v => v.toFixed(2)));
};
session.requestAnimationFrame(onFrame);
Lichtrichtung im local-Raum: ["0.10", "0.96", "-0.25"]

Reflexions-Cubemap bei reflectionchange aktualisieren

const gl = canvas.getContext('webgl2', { xrCompatible: true });
const binding = new XRWebGLBinding(session, gl);

// HDR nutzen, falls das Gerät es bevorzugt
const lightProbe = await session.requestLightProbe({
  reflectionFormat: session.preferredReflectionFormat ?? 'srgba8'
});

let envCubeMap = null;
const updateCubeMap = () => {
  envCubeMap = binding.getReflectionCubeMap(lightProbe); // WebGLTexture | null
  console.log('Neue Reflexions-Cubemap:', envCubeMap !== null);
};

lightProbe.addEventListener('reflectionchange', updateCubeMap);
// alternativ: lightProbe.onreflectionchange = updateCubeMap;

// beim Sitzungsende aufräumen
session.addEventListener('end', () => {
  lightProbe.removeEventListener('reflectionchange', updateCubeMap);
});
Neue Reflexions-Cubemap: true

// Wichtig · Fallstricke

  • Experimentell: Die API wird nur in Chromium-Browsern auf Android mit ARCore unterstützt (ab Chrome 90). Firefox, Safari und Desktop-Browser bieten sie nicht an. Prüfe vorher mit 'requestLightProbe' in XRSession.prototype, ob sie vorhanden ist, und fordere "light-estimation" am besten als optionalFeatures an, damit die AR-Sitzung auch ohne Lichtschätzung startet.
  • Nur in sicheren Kontexten (HTTPS) verfügbar. getLightEstimate() kann in den ersten Frames null liefern – prüfe das immer.
  • Datenschutz: Lichtdaten können Rückschlüsse auf die Umgebung erlauben. Browser runden oder vergröbern die Werte deshalb und aktualisieren sie seltener. Rechne nicht mit Messwerten in Sensorqualität.
  • getReflectionCubeMap() erzeugt jedes Mal eine neue Textur. Ruf die Methode nur bei reflectionchange auf und nicht in jedem Frame, sonst sinkt die Leistung und die GPU verliert Speicher. Nicht mehr benötigte Texturen gibst du mit gl.deleteTexture() frei.
  • Für "rgba16f" braucht es WebGL 2 bzw. die passende Erweiterung für Gleitkommatexturen. Wird das Format nicht unterstützt, wird das Promise abgelehnt.