Start · Sprachen · JavaScript · Referenz · XRCPUDepthInformation.data

XRCPUDepthInformation.data

Eigenschaft

Schreibgeschützter <code>ArrayBuffer</code> mit den rohen Tiefenwerten des aktuellen WebXR-Frames, die auf der CPU ausgelesen werden.

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

Signatur

XRCPUDepthInformation.data

Beschreibung

Die schreibgeschützte Eigenschaft data eines XRCPUDepthInformation-Objekts enthält den Tiefenpuffer des aktuellen Frames als ArrayBuffer. Das Objekt bekommt man in einer AR-Sitzung mit dem Feature "depth-sensing" und der Nutzungsart "cpu-optimized" über XRFrame.getDepthInformation(view).

Wie der Puffer aufgebaut ist, hängt von XRSession.depthDataFormat ab:

  • "luminance-alpha" bzw. "unsigned-short": 2 Byte pro Pixel. Man liest ihn am besten über ein Uint16Array aus.
  • "float32": 4 Byte pro Pixel. Man liest ihn über ein Float32Array aus.

Die Pixel liegen zeilenweise hintereinander (Index = x + y * width). Die Maße stehen in width und height. Die Rohwerte sind noch keine Meter. Man multipliziert sie mit rawValueToMeters, um die Entfernung in Metern zu erhalten. Wenn man nur einzelne Punkte braucht, ist getDepthInMeters(x, y) einfacher. Diese Methode rechnet mit normierten Bildkoordinaten und berücksichtigt normDepthBufferFromNormView gleich mit.

Direkten Zugriff auf data braucht man, wenn man viele Pixel auf einmal verarbeiten will, zum Beispiel für eine Verdeckung (Occlusion) per Software, für Kollisionsprüfungen, zum Erzeugen eines Punkte-Netzes oder um eine Tiefenkarte als Bild darzustellen.

Rückgabewert

Typ
ArrayBuffer
Beschreibung
Rohdaten des Tiefenpuffers. Die Größe ist width * height * Bytes pro Pixel (2 Byte bei "luminance-alpha"/"unsigned-short", 4 Byte bei "float32").

Beispiele

Sitzung mit CPU-Tiefendaten starten

const session = await navigator.xr.requestSession('immersive-ar', {
  requiredFeatures: ['depth-sensing', 'local'],
  depthSensing: {
    usagePreference: ['cpu-optimized'],
    dataFormatPreference: ['luminance-alpha', 'float32']
  }
});

console.log('Nutzung:', session.depthUsage);
console.log('Format:', session.depthDataFormat);
Nutzung: cpu-optimized Format: luminance-alpha

Puffer je nach Format als typisiertes Array auslesen

const refSpace = await session.requestReferenceSpace('local');

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;

  for (const view of pose.views) {
    const depth = frame.getDepthInformation(view);
    if (!depth) continue;

    // Passende Sicht auf den ArrayBuffer wählen
    const values = session.depthDataFormat === 'float32'
      ? new Float32Array(depth.data)
      : new Uint16Array(depth.data);

    // Pixel in der Bildmitte in Meter umrechnen
    const cx = Math.floor(depth.width / 2);
    const cy = Math.floor(depth.height / 2);
    const raw = values[cx + cy * depth.width];
    console.log(`Mitte: ${(raw * depth.rawValueToMeters).toFixed(2)} m`);
  }
};
session.requestAnimationFrame(onFrame);
Mitte: 1.37 m

Nächsten Punkt im Tiefenbild finden (z. B. für Kollisionswarnung)

const findNearest = (depth, format) => {
  const values = format === 'float32'
    ? new Float32Array(depth.data)
    : new Uint16Array(depth.data);

  let min = Infinity;
  let minIndex = -1;
  for (let i = 0; i < values.length; i++) {
    const v = values[i];
    if (v > 0 && v < min) { // 0 = kein gültiger Messwert
      min = v;
      minIndex = i;
    }
  }
  return {
    meters: min * depth.rawValueToMeters,
    x: minIndex % depth.width,
    y: Math.floor(minIndex / depth.width)
  };
};

// Innerhalb des Frame-Callbacks aufrufen:
// const nearest = findNearest(frame.getDepthInformation(view), session.depthDataFormat);
// if (nearest.meters < 0.5) console.warn('Hindernis sehr nah!', nearest);
Hindernis sehr nah! { meters: 0.42, x: 80, y: 45 }

// Wichtig · Fallstricke

  • Nur im aktiven Frame gültig: Die Daten dürfen nur im requestAnimationFrame-Callback des zugehörigen XRFrame gelesen werden. Danach löst ein Zugriff einen InvalidStateError aus. Wer die Werte später noch braucht, kopiert sie vorher, z. B. mit depth.data.slice(0).
  • Format beachten: Ob die Werte als Uint16Array oder als Float32Array gelesen werden müssen, hängt immer von session.depthDataFormat ab. Mit der falschen Sicht auf den Puffer bekommt man unsinnige Werte, aber keine Fehlermeldung.
  • Rohwerte sind keine Meter: Man muss immer mit rawValueToMeters multiplizieren. Der Wert 0 bedeutet meist, dass es an dieser Stelle keine gültige Messung gibt.
  • Koordinatensysteme: Das Tiefenbild ist nicht unbedingt genauso ausgerichtet wie die Ansicht, und seine Auflösung ist meist deutlich niedriger. Für Punkte in Bildschirmkoordinaten sollte man normDepthBufferFromNormView verwenden oder gleich getDepthInMeters().
  • Bei "gpu-optimized" gibt es dieses Objekt nicht. Dann liefert XRWebGLBinding.getDepthInformation() eine Textur.
  • Kompatibilität: Die Eigenschaft ist experimentell und funktioniert derzeit nur in Chromium-Browsern auf Android-Geräten mit ARCore-Tiefenunterstützung. Sie setzt einen sicheren Kontext (HTTPS) voraus.
  • Leistung: Wer jeden Frame über alle Pixel läuft, belastet den Hauptthread. Besser ist es, nur einen Teil der Pixel auszuwerten (Unterabtastung) oder die Arbeit in einen Worker auszulagern (vorher kopieren).