Signatur
Beschreibung
Die schreibgeschützte Eigenschaft normDepthBufferFromNormView des Interfaces XRDepthInformation liefert ein XRRigidTransform. Diese Transformation rechnet einen Punkt in normalisierten View-Koordinaten (Ursprung oben links, Wertebereich 0–1 auf beiden Achsen) in normalisierte Koordinaten des Tiefenpuffers um. Der Tiefenpuffer des Geräts ist nämlich nicht zwangsläufig genauso ausgerichtet wie die gerenderte Ansicht: Er kann zum Beispiel wegen der Bildschirmausrichtung gedreht oder gespiegelt sein.
Brauchen wirst du die Eigenschaft immer dann, wenn du selbst auf die Rohdaten des Tiefenpuffers zugreifst. Das betrifft vor allem zwei Fälle:
- den direkten Zugriff auf
XRCPUDepthInformation.dataauf der CPU, zum Beispiel für eigene Filter oder eine Kollisionsprüfung, und - das Auslesen der Tiefentextur aus
XRWebGLDepthInformation.texturein einem Shader, etwa für Verdeckung (Occlusion) oder Physik-Effekte.
Für einzelne Punkte kannst du auf der CPU auch einfach XRCPUDepthInformation.getDepthInMeters(x, y) aufrufen. Diese Methode wendet die Transformation bereits intern an.
Die Matrix erhältst du über normDepthBufferFromNormView.matrix als Float32Array mit 16 Werten in spaltenweiser Anordnung (column-major). Du kannst sie direkt mit gl.uniformMatrix4fv() an WebGL übergeben. Umgekehrt findest du die Rücktransformation unter normDepthBufferFromNormView.inverse.
Rückgabewert
matrix enthält die 4×4-Matrix als Float32Array in spaltenweiser Anordnung.Beispiele
Session mit Tiefenerkennung starten und die Matrix auslesen
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['depth-sensing'],
depthSensing: {
usagePreference: ['cpu-optimized'],
dataFormatPreference: ['luminance-alpha']
}
});
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 depthInfo = frame.getDepthInformation(view);
if (!depthInfo) continue;
// 4x4-Matrix, spaltenweise angeordnet
console.log(depthInfo.normDepthBufferFromNormView.matrix);
}
};
session.requestAnimationFrame(onFrame);
Rohdaten auf der CPU manuell auslesen
// x, y: normalisierte View-Koordinaten (0..1, Ursprung oben links)
const depthAt = (depthInfo, x, y) => {
const m = depthInfo.normDepthBufferFromNormView.matrix;
// Punkt (x, y, 0, 1) mit der spaltenweisen Matrix transformieren
const u = m[0] * x + m[4] * y + m[12];
const v = m[1] * x + m[5] * y + m[13];
const { width, height, rawValueToMeters } = depthInfo;
const col = Math.min(width - 1, Math.max(0, Math.floor(u * width)));
const row = Math.min(height - 1, Math.max(0, Math.floor(v * height)));
// Format 'luminance-alpha' = 16 Bit pro Pixel
const raw = new Uint16Array(depthInfo.data)[row * width + col];
return raw * rawValueToMeters;
};
// innerhalb des Animation-Frame-Callbacks:
// const meters = depthAt(depthInfo, 0.5, 0.5);
// Kontrolle: depthInfo.getDepthInMeters(0.5, 0.5) liefert denselben Wert
// console.log(meters.toFixed(2));
Matrix als Uniform an einen WebGL-Shader übergeben (GPU-Pfad)
// Fragment-Shader (GLSL ES 1.0)
const fragmentSrc = `
precision mediump float;
uniform sampler2D uDepthTexture;
uniform mat4 uUvTransform;
uniform float uRawValueToMeters;
varying vec2 vViewUv; // normalisierte View-Koordinaten
float depthInMeters(vec2 viewUv) {
vec2 depthUv = (uUvTransform * vec4(viewUv, 0.0, 1.0)).xy;
vec2 packed = texture2D(uDepthTexture, depthUv).ra; // luminance-alpha
return dot(packed, vec2(255.0, 256.0 * 255.0)) * uRawValueToMeters;
}
void main() {
float d = depthInMeters(vViewUv);
gl_FragColor = vec4(vec3(clamp(d / 5.0, 0.0, 1.0)), 1.0);
}
`;
// im Frame-Callback (Session mit usagePreference: ['gpu-optimized'])
const drawDepth = (gl, glBinding, view, program) => {
const depthInfo = glBinding.getDepthInformation(view);
if (!depthInfo) return;
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, depthInfo.texture);
gl.uniform1i(gl.getUniformLocation(program, 'uDepthTexture'), 0);
gl.uniformMatrix4fv(
gl.getUniformLocation(program, 'uUvTransform'),
false,
depthInfo.normDepthBufferFromNormView.matrix
);
gl.uniform1f(
gl.getUniformLocation(program, 'uRawValueToMeters'),
depthInfo.rawValueToMeters
);
// ... Vollbild-Quad zeichnen
};