Signatur
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. Mitframe.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, umgetReflectionCubeMap()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
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);
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);
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);
});
// 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 alsoptionalFeaturesan, damit die AR-Sitzung auch ohne Lichtschätzung startet. - Nur in sicheren Kontexten (HTTPS) verfügbar.
getLightEstimate()kann in den ersten Framesnullliefern – 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 beireflectionchangeauf und nicht in jedem Frame, sonst sinkt die Leistung und die GPU verliert Speicher. Nicht mehr benötigte Texturen gibst du mitgl.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.