Signatur
Beschreibung
XRCPUDepthInformation gehört zum WebXR Depth Sensing Module. Das Interface stellt den Tiefenpuffer einer einzelnen XRView als ArrayBuffer bereit, den dein JavaScript-Code direkt auslesen kann. Damit misst du, wie weit reale Oberflächen von der Kamera entfernt sind. Das brauchst du etwa für Verdeckung (Occlusion), Physik, Kollisionen oder Abstandsmessungen in AR-Anwendungen.
Du bekommst eine Instanz über XRFrame.getDepthInformation(view). Das funktioniert nur, wenn die Sitzung mit dem Feature "depth-sensing" angefordert wurde und der Browser session.depthUsage === "cpu-optimized" gewählt hat. Bei "gpu-optimized" verwendest du stattdessen XRWebGLBinding.getDepthInformation(), das eine XRWebGLDepthInformation mit Textur zurückgibt.
Diese Mitglieder sind wichtig:
data(ArrayBuffer, nur lesbar): die Rohdaten des Tiefenpuffers. Je nachsession.depthDataFormatliest du sie alsUint16Array("luminance-alpha"bzw."unsigned-short") oder alsFloat32Array("float32").getDepthInMeters(x, y): gibt die Tiefe in Metern an einer normalisierten Ansichtskoordinate zurück.- Von
XRDepthInformationgeerbt:width,height,rawValueToMeters(Umrechnungsfaktor für Rohwerte) undnormDepthBufferFromNormView(XRRigidTransformvon normalisierten Ansichts- in Tiefenpuffer-Koordinaten).
Für einzelne Messpunkte, etwa in der Bildschirmmitte, reicht getDepthInMeters(). Wenn du viele Pixel verarbeitest, zum Beispiel für eine Punktwolke oder ein Gitter, liest du data besser direkt über ein Typed Array. Das ist deutlich schneller.
Rückgabewert
getDepthInMeters(x, y) gibt den Abstand in Metern von der Ansichtsebene zur realen Oberfläche am angegebenen Punkt zurück. Liegen x oder y außerhalb von [0, 1], wirft die Methode einen RangeError.Beispiele
AR-Sitzung mit CPU-Tiefenerkennung anfordern
const startAR = async () => {
if (!navigator.xr || !(await navigator.xr.isSessionSupported('immersive-ar'))) {
console.warn('WebXR AR wird nicht unterstützt');
return;
}
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['depth-sensing'],
depthSensing: {
usagePreference: ['cpu-optimized', 'gpu-optimized'],
dataFormatPreference: ['luminance-alpha', 'float32']
}
});
// Die tatsächlich gewählte Konfiguration prüfen
console.log('Nutzung:', session.depthUsage);
console.log('Format:', session.depthDataFormat);
return session;
};
// Muss durch eine Nutzergeste ausgelöst werden
document.querySelector('#ar-button').addEventListener('click', startAR);
Abstand in der Bildmitte messen
const onXRFrame = (time, frame) => {
const session = frame.session;
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
for (const view of pose.views) {
const depthInfo = frame.getDepthInformation(view);
if (!depthInfo) continue; // noch keine Tiefendaten verfügbar
const meters = depthInfo.getDepthInMeters(0.5, 0.5);
document.querySelector('#distance').textContent =
`Abstand: ${meters.toFixed(2)} m`;
}
};
session.requestAnimationFrame(onXRFrame);
Rohdaten direkt auslesen (schnell für viele Pixel)
const readDepthBuffer = (depthInfo, format) => {
const { width, height, rawValueToMeters, data } = depthInfo;
const values = format === 'float32'
? new Float32Array(data)
: new Uint16Array(data); // luminance-alpha / unsigned-short
let nearest = Infinity;
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const raw = values[row * width + col];
if (raw === 0) continue; // 0 = keine gültige Messung
nearest = Math.min(nearest, raw * rawValueToMeters);
}
}
return { width, height, nearest };
};
// Innerhalb des XR-Frame-Callbacks aufrufen:
// const depthInfo = frame.getDepthInformation(view);
// console.log(readDepthBuffer(depthInfo, session.depthDataFormat));
// Wichtig · Fallstricke
- Nur im aktiven Frame gültig: Du kannst auf
dataundgetDepthInMeters()nur innerhalb desrequestAnimationFrame-Callbacks zugreifen, zu dem derXRFramegehört. Danach wirft der Zugriff einenInvalidStateError. Wenn du die Daten später brauchst, kopiere sie vorher, zum Beispiel mitdata.slice(0). - Nutzungsart prüfen: Hat der Browser
"gpu-optimized"gewählt, wirftXRFrame.getDepthInformation()einenNotSupportedError. Prüfe deshalb immersession.depthUsage. - Koordinatensysteme:
getDepthInMeters()erwartet normalisierte Ansichtskoordinaten. Die Indizes indatabeziehen sich dagegen auf den Tiefenpuffer. Um zwischen beiden umzurechnen, nutzt dunormDepthBufferFromNormView.matrix, besonders wenn das Gerät gedreht ist. - Auflösung: Der Tiefenpuffer hat meist eine viel geringere Auflösung als das Kamerabild, oft etwa 160×90. Er kann außerdem Lücken enthalten (Rohwert
0). - Kompatibilität: Das Interface ist experimentell und derzeit praktisch nur in Chromium-Browsern auf ARCore-fähigen Android-Geräten verfügbar. Es setzt einen sicheren Kontext (HTTPS) voraus, und das Feature
"depth-sensing"muss inrequiredFeaturesoderoptionalFeaturesangefordert werden. - Datenschutz: Tiefendaten verraten viel über die Umgebung des Nutzers. Der Browser kann dafür eine gesonderte Einwilligung verlangen.