Signatur
Beschreibung
Die schreibgeschützte Eigenschaft texture eines XRWebGLDepthInformation-Objekts enthält ein WebGLTexture mit dem Tiefenpuffer, den das Gerät für die aktuelle Ansicht (XRView) ermittelt hat. Das Objekt bekommst du über XRWebGLBinding.getDepthInformation(view). Das geht nur, wenn die Sitzung mit dem Feature "depth-sensing" und der Nutzungspräferenz "gpu-optimized" gestartet wurde.
Die Textur ist undurchsichtig (opaque): Du kannst sie binden und im Shader abtasten, aber nicht mit gl.deleteTexture() löschen, nicht per texImage2D verändern und ihre Daten nicht direkt auf die CPU zurücklesen. Typische Einsatzzwecke sind Verdeckung (virtuelle Objekte verschwinden hinter echten Gegenständen), physikbasierte Effekte und die Visualisierung von Tiefe, alles direkt auf der GPU ohne Umweg über JavaScript-Arrays.
Welches Format die Rohwerte haben, legt session.depthDataFormat fest, z. B. "luminance-alpha" (2 Byte pro Texel in den Kanälen L und A), "float32" oder "unsigned-short". Um daraus Meter zu berechnen, multiplizierst du den Rohwert im Shader mit rawValueToMeters. Die Texturkoordinaten rechnest du mit normDepthBufferFromNormView vom normalisierten Ansichtsraum in den Tiefenpuffer um. Beide Werte erbt das Objekt von XRDepthInformation.
Rückgabewert
width × height Texel groß. Sie gilt nur innerhalb des requestAnimationFrame-Callbacks, in dem sie abgerufen wurde.Beispiele
Sitzung mit GPU-optimierter Tiefenerkennung starten
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['depth-sensing'],
depthSensing: {
usagePreference: ['gpu-optimized'],
dataFormatPreference: ['luminance-alpha', 'float32']
}
});
console.log('Nutzung:', session.depthUsage);
console.log('Format:', session.depthDataFormat);
const glBinding = new XRWebGLBinding(session, gl);
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
Tiefentextur im Render-Loop an einen Shader binden
// Voraussetzungen: session, gl, glBinding, program und refSpace sind bereits angelegt
const uDepth = gl.getUniformLocation(program, 'uDepthTexture');
const uUvTransform = gl.getUniformLocation(program, 'uUvTransform');
const uRawToMeters = gl.getUniformLocation(program, 'uRawValueToMeters');
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);
if (!depthInfo) continue; // Noch keine Tiefendaten vorhanden
gl.useProgram(program);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, depthInfo.texture);
gl.uniform1i(uDepth, 0);
gl.uniformMatrix4fv(uUvTransform, false,
depthInfo.normDepthBufferFromNormView.matrix);
gl.uniform1f(uRawToMeters, depthInfo.rawValueToMeters);
// ... Szene für diese Ansicht zeichnen
}
};
session.requestAnimationFrame(onXRFrame);
Fragment-Shader: Rohwert (luminance-alpha) in Meter umrechnen
const depthFragmentShader = `#version 300 es
precision highp float;
uniform sampler2D uDepthTexture;
uniform mat4 uUvTransform;
uniform float uRawValueToMeters;
in vec2 vUv; // normalisierte Ansichtskoordinaten 0..1
out vec4 fragColor;
float depthInMeters(vec2 uv) {
vec2 depthUv = (uUvTransform * vec4(uv, 0.0, 1.0)).xy;
// luminance-alpha: zwei Bytes (L = niederwertig, A = höherwertig)
vec2 packed = texture(uDepthTexture, depthUv).ra;
return dot(packed, vec2(255.0, 256.0 * 255.0)) * uRawValueToMeters;
}
void main() {
float d = depthInMeters(vUv);
// Tiefe als Graustufen darstellen (0–5 m)
fragColor = vec4(vec3(clamp(d / 5.0, 0.0, 1.0)), 1.0);
}`;
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, depthFragmentShader);
gl.compileShader(shader);
console.log(gl.getShaderParameter(shader, gl.COMPILE_STATUS));
// Wichtig · Fallstricke
- Nur im Frame gültig: Die Textur und das
XRWebGLDepthInformation-Objekt gelten nur im aktuellenrequestAnimationFrame-Callback. Speicherst du sie für spätere Frames, liest du ungültige Daten oder bekommst WebGL-Fehler. - Nur bei
"gpu-optimized": Hat der Browser"cpu-optimized"gewählt, wirftXRWebGLBinding.getDepthInformation()einenInvalidStateError. In diesem Fall nutzt duXRFrame.getDepthInformation()undXRCPUDepthInformation.data. Prüfe deshalbsession.depthUsage. - Format beachten: Wie du im Shader dekodierst, hängt von
session.depthDataFormatab. Bei"float32"genügttexture(...).r * rawValueToMeters. Bei"luminance-alpha"musst du zwei Kanäle kombinieren. Float-Texturen setzen unter Umständen WebGL2 bzw. passende Erweiterungen voraus. - Undurchsichtig:
gl.deleteTexture(),texImage2Dund das Anhängen an einen Framebuffer zum Zurücklesen sind nicht erlaubt. - Neuere Spezifikation: Neuere Entwürfe führen
textureType("texture"oder"texture-array") undimageIndexein. Bei einem Array bindest du die Textur angl.TEXTURE_2D_ARRAY. - Kompatibilität: Die Eigenschaft ist experimentell und setzt einen sicheren Kontext (HTTPS) voraus. Unterstützt wird sie derzeit nur von Chromium-Browsern auf Android-Geräten mit ARCore-Tiefenunterstützung, nicht von Firefox und Safari.