Signatur
Beschreibung
XRWebGLDepthInformation gehört zum WebXR Depth Sensing Module. Es enthält die vom Gerät geschätzte Tiefe der realen Umgebung (Abstand Kamera → Oberfläche) für eine bestimmte XRView und stellt sie als WebGLTexture direkt auf der GPU bereit. Ein Objekt erhältst du nur über XRWebGLBinding.getDepthInformation(view); einen öffentlichen Konstruktor gibt es nicht.
Typische Einsatzfälle sind Verdeckung (Occlusion) – virtuelle Objekte verschwinden hinter echten Möbeln oder Personen –, physikalische Effekte wie Kollisionen mit der realen Umgebung oder Visualisierungen der Tiefenkarte. Weil die Daten bereits als Textur vorliegen, kannst du sie ohne teures Kopieren von der CPU im Fragment-Shader auswerten. Für CPU-Zugriff gibt es das Gegenstück XRCPUDepthInformation.
Neben den eigenen Eigenschaften erbt das Interface von XRDepthInformation:
texture(WebGLTexture, nur lesbar) – die Tiefentextur.textureType("texture"|"texture-array") undimageIndex– bei Textur-Arrays die Schicht der jeweiligen Ansicht (neuere Spezifikationsstände).width,height– Auflösung der Tiefenkarte (geerbt).normDepthBufferFromNormView(XRRigidTransform) – Transformation von normalisierten Ansichtskoordinaten in Tiefenpuffer-Koordinaten (geerbt).rawValueToMeters(number) – Faktor, mit dem Rohwerte in Meter umgerechnet werden (geerbt).
Voraussetzung ist eine immersive-ar-Sitzung mit dem Feature "depth-sensing" und der Nutzungspräferenz "gpu-optimized". Das Datenformat (session.depthDataFormat, z. B. "luminance-alpha" oder "float32") bestimmt, wie du die Texel im Shader decodierst.
Rückgabewert
XRWebGLBinding.getDepthInformation(view) geliefert – oder null, wenn für diesen Frame keine Tiefendaten vorliegen.Beispiele
AR-Sitzung mit GPU-Tiefenerkennung anfordern
const startAR = async () => {
if (!(await navigator.xr?.isSessionSupported('immersive-ar'))) {
console.warn('immersive-ar wird nicht unterstützt');
return;
}
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['depth-sensing'],
depthSensing: {
usagePreference: ['gpu-optimized'],
dataFormatPreference: ['luminance-alpha', 'float32']
}
});
console.log('Nutzung:', session.depthUsage); // z. B. "gpu-optimized"
console.log('Format:', session.depthDataFormat); // z. B. "luminance-alpha"
return session;
};
document.querySelector('#ar-button').addEventListener('click', startAR);
Tiefentextur im Render-Loop an den Shader binden
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const run = async (session, program) => {
await session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
const refSpace = await session.requestReferenceSpace('local');
const binding = new XRWebGLBinding(session, gl);
const uDepth = gl.getUniformLocation(program, 'uDepthTexture');
const uUvTransform = gl.getUniformLocation(program, 'uUvTransform');
const uRawToMeters = gl.getUniformLocation(program, 'uRawValueToMeters');
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
for (const view of pose.views) {
const depthInfo = binding.getDepthInformation(view);
if (!depthInfo) continue; // noch keine Tiefendaten
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 zeichnen
}
};
session.requestAnimationFrame(onFrame);
};
Fragment-Shader: Tiefe decodieren und Verdeckung berechnen
// GLSL-Quelltext für das Format "luminance-alpha" (WebGL 2)
const fragmentShaderSource = `#version 300 es
precision highp float;
uniform sampler2D uDepthTexture;
uniform mat4 uUvTransform;
uniform float uRawValueToMeters;
in vec2 vViewUv; // normalisierte Ansichtskoordinaten 0..1
in float vVirtualDepth; // Tiefe des virtuellen Fragments in Metern
out vec4 fragColor;
float realDepthMeters(vec2 uv) {
vec2 depthUv = (uUvTransform * vec4(uv, 0.0, 1.0)).xy;
// 16-Bit-Wert ist auf Luminanz (niedrig) und Alpha (hoch) verteilt
vec2 packed = texture(uDepthTexture, depthUv).ra;
return dot(packed, vec2(255.0, 256.0 * 255.0)) * uRawValueToMeters;
}
void main() {
// virtuelles Objekt verwerfen, wenn es hinter realer Geometrie liegt
if (vVirtualDepth > realDepthMeters(vViewUv)) discard;
fragColor = vec4(0.2, 0.6, 1.0, 1.0);
}`;
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fragmentShaderSource);
gl.compileShader(shader);
console.log(gl.getShaderParameter(shader, gl.COMPILE_STATUS));