Signatur
Beschreibung
XRPose ist ein Interface der WebXR Device API und steht für eine Pose, also Position plus Orientierung eines Objekts im 3D-Raum. Eine Pose gilt immer nur relativ zu einem Basis-Raum (XRSpace bzw. XRReferenceSpace). Ohne diesen Basis-Raum haben die Werte keine Bedeutung.
Einen XRPose erzeugt man nie selbst. Man bekommt ihn innerhalb eines Animations-Callbacks über XRFrame.getPose(space, baseSpace), etwa für einen Controller (inputSource.gripSpace oder targetRaySpace). Die abgeleitete Klasse XRViewerPose liefert XRFrame.getViewerPose(referenceSpace). Sie beschreibt die Pose des Betrachters, also des Headsets, und enthält zusätzlich das Array views für das Rendern pro Auge.
Wichtige Eigenschaften (alle schreibgeschützt):
transform(XRRigidTransform): Position (position,DOMPointReadOnly), Orientierung als Quaternion (orientation) und eine fertige 4×4-Matrix (matrix,Float32Array, spaltenweise). Die Matrix lässt sich direkt an WebGL bzw. three.js übergeben.emulatedPosition(boolean):true, wenn die Position nicht gemessen, sondern geschätzt ist. Das ist z. B. bei reinem 3DoF-Tracking oder nach Verlust des Trackings der Fall.linearVelocity(DOMPointReadOnly | null): Geschwindigkeit in Metern pro Sekunde, sofern das Gerät sie liefert.angularVelocity(DOMPointReadOnly | null): Winkelgeschwindigkeit in Radiant pro Sekunde, sofern verfügbar.
Typische Einsätze sind: Controller-Modelle an die richtige Stelle setzen, Zeigestrahlen (Ray-Casting) berechnen, Objekte werfen (mit linearVelocity) und die Kamera eines XR-Renderers aktualisieren.
Rückgabewert
XRFrame.getPose() geliefert. Ist null, wenn sich die Pose gerade nicht bestimmen lässt, z. B. weil das Tracking verloren ist.Beispiele
Controller-Pose im Frame-Loop abfragen
const startXR = async () => {
const session = await navigator.xr.requestSession('immersive-vr');
const refSpace = await session.requestReferenceSpace('local-floor');
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
for (const source of session.inputSources) {
if (!source.gripSpace) continue;
// XRPose relativ zum Boden-Referenzraum
const pose = frame.getPose(source.gripSpace, refSpace);
if (!pose) continue; // Tracking aktuell nicht verfügbar
const { x, y, z } = pose.transform.position;
console.log(`${source.handedness}: ${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)}`);
}
};
session.requestAnimationFrame(onFrame);
};
document.querySelector('#enter-vr').addEventListener('click', startXR);
Pose-Matrix direkt in WebGL verwenden
// gl, program und refSpace wurden vorher eingerichtet
const uModel = gl.getUniformLocation(program, 'uModelMatrix');
const drawController = (frame, source, refSpace) => {
const pose = frame.getPose(source.gripSpace, refSpace);
if (!pose) return;
// Float32Array mit 16 Werten, spaltenweise – passt direkt zu WebGL
gl.uniformMatrix4fv(uModel, false, pose.transform.matrix);
gl.drawArrays(gl.TRIANGLES, 0, 36);
};
Wurfgeschwindigkeit und geschätzte Position auswerten
const onSelectEnd = (event) => {
const { frame, inputSource } = event;
const pose = frame.getPose(inputSource.gripSpace, refSpace);
if (!pose) return;
if (pose.emulatedPosition) {
console.warn('Position nur geschätzt – Wurf ungenau');
}
// linearVelocity ist optional und kann null sein
const v = pose.linearVelocity ?? { x: 0, y: 0, z: 0 };
ball.velocity.set(v.x, v.y, v.z);
console.log('Wurf mit', Math.hypot(v.x, v.y, v.z).toFixed(2), 'm/s');
};
session.addEventListener('selectend', onSelectEnd);
// Wichtig · Fallstricke
- Nur im aktiven Frame gültig:
XRFrame.getPose()funktioniert nur innerhalb des Callbacks vonXRSession.requestAnimationFrame()oder eines Eingabe-Events wieselect. Außerhalb davon wird einInvalidStateErrorausgelöst. Poses sollte man nicht über Frames hinweg speichern. Wer die Werte später braucht, kopiert sie vorher. - Immer auf
nullprüfen: Geht das Tracking verloren, liefertgetPose()nullstatt einesXRPose. linearVelocityundangularVelocitywerden von vielen Geräten nicht unterstützt und sind dannnull. Die Geschwindigkeit sollte man in diesem Fall selbst aus den Positionen mehrerer Frames berechnen.emulatedPosition === trueheißt: Die Position ist geschätzt, z. B. bei 3DoF-Geräten. Positionsgenaue Interaktionen sollten dann vorsichtig behandelt werden.- Kompatibilität: WebXR braucht einen sicheren Kontext (HTTPS). Unterstützt wird es in Chromium-Browsern und im Meta Quest Browser. Firefox und Safari auf dem Desktop unterstützen es nicht, Safari auf der Vision Pro nur teilweise. Deshalb vorher mit
navigator.xr?.isSessionSupported()prüfen, ob WebXR verfügbar ist. Auf dem Desktop hilft der Immersive Web Emulator beim Testen. - Alle Werte sind in Metern und Radiant angegeben. Das Koordinatensystem ist rechtshändig: +Y zeigt nach oben, −Z nach vorn.