Signatur
Beschreibung
XRLightEstimate gehört zum Modul WebXR Lighting Estimation der WebXR Device API. In AR-Sitzungen schätzt das Gerät (z. B. über ARCore) aus dem Kamerabild, wie die reale Umgebung beleuchtet ist. Mit diesen Werten lassen sich virtuelle Objekte so beleuchten, dass sie zur echten Umgebung passen: Schatten fallen in die richtige Richtung, Farbstich und Helligkeit stimmen.
Es gibt keinen Konstruktor. Ein Objekt erhältst du pro Frame über XRFrame.getLightEstimate(lightProbe). Die dafür nötige XRLightProbe forderst du einmal mit XRSession.requestLightProbe() an. Die Sitzung muss mit dem Feature "light-estimation" gestartet worden sein.
Die Schnittstelle hat drei schreibgeschützte Eigenschaften:
primaryLightDirection(DOMPointReadOnly): Richtung zur stärksten Lichtquelle im Referenzraum der Light Probe.wist immer0.primaryLightIntensity(DOMPointReadOnly): RGB-Intensität dieses Hauptlichts inx,yundz.wist immer1.sphericalHarmonicsCoefficients(Float32Array): 27 Werte, also 9 sphärische Harmonische 2. Ordnung mit je 3 Werten für R, G und B. Sie beschreiben das diffuse Umgebungslicht aus allen Richtungen.
Typischer Ablauf: Du steuerst ein gerichtetes Licht (Directional Light) über Richtung und Intensität und füllst ein Umgebungslicht (z. B. THREE.LightProbe) mit den Koeffizienten.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $lightProbe Pflicht | XRLightProbe | Argument von XRFrame.getLightEstimate(), über das man ein XRLightEstimate erhält. Die Probe kommt aus XRSession.requestLightProbe(). |
Beispiele
AR-Sitzung mit Lichtschätzung starten und Light Probe anfordern
const startAR = async () => {
if (!navigator.xr || !(await navigator.xr.isSessionSupported('immersive-ar'))) {
console.warn('Immersive AR wird nicht unterstützt.');
return;
}
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['local'],
optionalFeatures: ['light-estimation']
});
if (!session.enabledFeatures?.includes('light-estimation')) {
console.warn('Lichtschätzung ist nicht verfügbar.');
}
// Probe einmalig anfordern (optional mit Reflexionsformat)
const lightProbe = await session.requestLightProbe({ reflectionFormat: 'srgba8' });
console.log('Light Probe bereit:', lightProbe);
return { session, lightProbe };
};
// Muss aus einer Benutzeraktion heraus aufgerufen werden
document.querySelector('#ar-button').addEventListener('click', startAR);
Lichtwerte pro Frame auslesen
const onXRFrame = (time, frame) => {
const session = frame.session;
session.requestAnimationFrame(onXRFrame);
const estimate = frame.getLightEstimate(lightProbe);
if (!estimate) return; // noch keine Schätzung vorhanden
const { x: dx, y: dy, z: dz } = estimate.primaryLightDirection;
const { x: r, y: g, z: b } = estimate.primaryLightIntensity;
console.log(`Richtung: (${dx.toFixed(2)}, ${dy.toFixed(2)}, ${dz.toFixed(2)})`);
console.log(`Intensität RGB: ${r.toFixed(2)}, ${g.toFixed(2)}, ${b.toFixed(2)}`);
console.log('SH-Koeffizienten:', estimate.sphericalHarmonicsCoefficients.length);
};
session.requestAnimationFrame(onXRFrame);
Schätzung auf three.js-Lichter übertragen
import * as THREE from 'three';
const directionalLight = new THREE.DirectionalLight();
const ambientProbe = new THREE.LightProbe();
scene.add(directionalLight, ambientProbe);
const applyLightEstimate = (estimate) => {
const dir = estimate.primaryLightDirection;
const int = estimate.primaryLightIntensity;
// Das Licht sitzt in der Richtung, aus der es kommt
directionalLight.position.set(dir.x, dir.y, dir.z).multiplyScalar(10);
// Stärkster Kanal = Intensität, die normierten Werte = Farbe
const max = Math.max(int.x, int.y, int.z, 0.0001);
directionalLight.intensity = max;
directionalLight.color.setRGB(int.x / max, int.y / max, int.z / max);
// 9 × RGB = 27 Werte direkt übernehmen
ambientProbe.sh.fromArray(estimate.sphericalHarmonicsCoefficients);
};
renderer.setAnimationLoop((time, frame) => {
const estimate = frame?.getLightEstimate(lightProbe);
if (estimate) applyLightEstimate(estimate);
renderer.render(scene, camera);
});