Signatur
Beschreibung
XRDepthInformation gehört zum WebXR Depth Sensing Module. Das Interface beschreibt einen Tiefenpuffer: ein Raster mit Werten, die für jeden Bildpunkt angeben, wie weit die reale Geometrie (Wände, Böden, Möbel, Hände) vom Gerät entfernt ist. So lassen sich in AR-Anwendungen virtuelle Objekte korrekt hinter realen Gegenständen verdecken (Occlusion), Physik mit der echten Umgebung umsetzen oder Abstände messen.
Instanzen erzeugt man nie selbst. Man bekommt sie über eine der beiden Unterklassen:
XRCPUDepthInformation: liefertXRFrame.getDepthInformation(view), wenn die Sitzung"cpu-optimized"nutzt. Die Rohdaten stehen alsArrayBuffer(data) bereit, dazu gibt es die MethodegetDepthInMeters(x, y).XRWebGLDepthInformation: liefertXRWebGLBinding.getDepthInformation(view), wenn die Sitzung"gpu-optimized"nutzt. Die Daten liegen dann als WebGL-Textur (texture) vor.
Das Basis-Interface selbst hat diese schreibgeschützten Eigenschaften:
widthundheight(number): Breite und Höhe des Tiefenpuffers in Werten. Sie weichen meist deutlich von der Auflösung der Kamera oder der Ansicht ab (z. B. 160×90).normDepthBufferFromNormView(XRRigidTransform): Transformation von normierten Ansichtskoordinaten (0..1) in normierte Koordinaten des Tiefenpuffers. Man braucht sie, weil der Puffer gegenüber der Ansicht gedreht oder gespiegelt sein kann.rawValueToMeters(number): Faktor, mit dem man einen Rohwert aus dem Puffer multipliziert, um Meter zu erhalten.
Tiefeninformationen sind nur innerhalb des requestAnimationFrame-Callbacks der XR-Sitzung und nur für den aktuellen Frame gültig. Wer außerhalb dieses Frames auf die Daten zugreift, bekommt eine InvalidStateError-Exception.
Rückgabewert
XRCPUDepthInformation oder XRWebGLDepthInformation) liefern XRFrame.getDepthInformation() bzw. XRWebGLBinding.getDepthInformation(). Beide Methoden geben null zurück, wenn für den Frame keine Tiefendaten vorliegen.Beispiele
AR-Sitzung mit Tiefenerkennung anfordern
const startAR = async () => {
if (!navigator.xr || !(await navigator.xr.isSessionSupported('immersive-ar'))) {
console.warn('immersive-ar wird nicht unterstützt');
return null;
}
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['depth-sensing'],
depthSensing: {
usagePreference: ['cpu-optimized', 'gpu-optimized'],
dataFormatPreference: ['luminance-alpha', 'float32']
}
});
// Welche Variante hat der Browser tatsächlich gewählt?
console.log('Nutzung:', session.depthUsage);
console.log('Format:', session.depthDataFormat);
return session;
};
// Muss durch eine Benutzeraktion ausgelöst werden
document.querySelector('#ar-start').addEventListener('click', startAR);
Entfernung in der Bildmitte messen (CPU)
const refSpace = await session.requestReferenceSpace('local');
const onXRFrame = (time, frame) => {
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
for (const view of pose.views) {
const depthInfo = frame.getDepthInformation(view); // XRCPUDepthInformation
if (!depthInfo) continue;
// Normierte Ansichtskoordinaten (0..1): Bildmitte
const meters = depthInfo.getDepthInMeters(0.5, 0.5);
console.log(`Puffer ${depthInfo.width}×${depthInfo.height}, Abstand Mitte: ${meters.toFixed(2)} m`);
}
};
session.requestAnimationFrame(onXRFrame);
Rohwerte manuell mit rawValueToMeters umrechnen
// Nur im Frame-Callback gültig; Format "luminance-alpha" = 16-Bit-Ganzzahlen
const readRawDepth = (depthInfo, col, row) => {
const raw = new Uint16Array(depthInfo.data);
const index = row * depthInfo.width + col;
return raw[index] * depthInfo.rawValueToMeters;
};
const onXRFrame = (time, frame) => {
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(refSpace);
const view = pose?.views[0];
const depthInfo = view && frame.getDepthInformation(view);
if (!depthInfo) return;
const col = Math.floor(depthInfo.width / 2);
const row = Math.floor(depthInfo.height / 2);
console.log('Rohwert-Abstand:', readRawDepth(depthInfo, col, row).toFixed(3), 'm');
};
session.requestAnimationFrame(onXRFrame);
Tiefentextur für Occlusion im Shader (GPU)
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const glBinding = new XRWebGLBinding(session, gl);
const onXRFrame = (time, frame) => {
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
for (const view of pose.views) {
const depthInfo = glBinding.getDepthInformation(view); // XRWebGLDepthInformation
if (!depthInfo) continue;
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, depthInfo.texture);
gl.uniform1i(uDepthTexture, 1);
gl.uniform1f(uRawValueToMeters, depthInfo.rawValueToMeters);
// Transformationsmatrix Ansicht -> Tiefenpuffer an den Shader übergeben
gl.uniformMatrix4fv(uUvTransform, false, depthInfo.normDepthBufferFromNormView.matrix);
// ... Szene zeichnen, im Fragment-Shader Tiefe vergleichen
}
};
session.requestAnimationFrame(onXRFrame);