Signatur
Beschreibung
getViewerPose() ist der zentrale Aufruf in jeder WebXR-Renderschleife. Innerhalb des Callbacks von XRSession.requestAnimationFrame() liefert die Methode die aktuelle Pose des Betrachters (Kopf bzw. Gerät) im übergebenen XRReferenceSpace. Das zurückgegebene XRViewerPose erbt von XRPose und enthält neben transform auch das Array views. Darin liegt ein XRView pro Auge oder Anzeige, jeweils mit eigener Projektionsmatrix und eigener Blickmatrix.
Aus diesen Views renderst du die Szene: Für jede XRView holst du über XRWebGLLayer.getViewport(view) den passenden Viewport und zeichnest die Szene mit view.projectionMatrix und view.transform.inverse.matrix (der Blickmatrix). Bei einem VR-Headset gibt es normalerweise zwei Views, bei Handheld-AR auf dem Smartphone einen.
Die Methode gibt null zurück, wenn das Tracking die Pose gerade nicht bestimmen kann, zum Beispiel beim Start, bei verdeckten Sensoren oder wenn das Tracking verloren geht. Behandle diesen Fall immer. Meist lässt du den Frame dann einfach aus oder zeichnest den letzten Zustand noch einmal. Die Eigenschaft emulatedPosition zeigt an, ob die Position nur geschätzt ist. Das ist etwa bei Geräten der Fall, die nur die Drehung erfassen (3DoF).
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $referenceSpace Pflicht | XRReferenceSpace | Der Referenzraum, in dem die Pose angegeben wird, z. B. aus session.requestReferenceSpace('local'), 'local-floor' oder 'bounded-floor'. |
Rückgabewert
XRViewerPose mit transform, views, emulatedPosition sowie gegebenenfalls linearVelocity und angularVelocity. null, wenn keine Pose verfügbar ist.Beispiele
Grundlegende Renderschleife mit WebGL
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const startXR = async () => {
const session = await navigator.xr.requestSession('immersive-vr');
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
const refSpace = await session.requestReferenceSpace('local-floor');
const onFrame = (time, frame) => {
frame.session.requestAnimationFrame(onFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return; // Tracking (noch) nicht verfügbar
const layer = frame.session.renderState.baseLayer;
gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
for (const view of pose.views) {
const vp = layer.getViewport(view);
gl.viewport(vp.x, vp.y, vp.width, vp.height);
// drawScene ist deine eigene Zeichenfunktion
drawScene(view.projectionMatrix, view.transform.inverse.matrix);
}
};
session.requestAnimationFrame(onFrame);
};
document.querySelector('#enter-vr').addEventListener('click', startXR);
Kopfposition und Tracking-Status auslesen
const logViewer = (frame, refSpace) => {
const pose = frame.getViewerPose(refSpace);
if (!pose) {
console.warn('Keine Betrachter-Pose – Tracking verloren?');
return;
}
const { x, y, z } = pose.transform.position;
console.log(`Kopf bei x=${x.toFixed(2)} y=${y.toFixed(2)} z=${z.toFixed(2)}`);
console.log('Anzahl Views:', pose.views.length);
console.log('Position geschätzt:', pose.emulatedPosition);
};
Betrachter verschieben mit einem versetzten Referenzraum
// Teleport: Der Nutzer soll 2 m weiter vorne stehen
const teleport = (refSpace) => {
const offset = new XRRigidTransform({ x: 0, y: 0, z: 2 });
return refSpace.getOffsetReferenceSpace(offset);
};
let viewSpace = await session.requestReferenceSpace('local-floor');
viewSpace = teleport(viewSpace);
session.requestAnimationFrame(function onFrame(t, frame) {
session.requestAnimationFrame(onFrame);
const pose = frame.getViewerPose(viewSpace);
if (pose) console.log(pose.transform.position.z.toFixed(2));
});
// Wichtig · Fallstricke
- Nur im aktiven Frame gültig: Rufe die Methode nur innerhalb des Callbacks von
XRSession.requestAnimationFrame()auf. Außerhalb davon oder bei einem gespeicherten, veraltetenXRFramewirft sie eineInvalidStateError-DOMException. - Immer auf
nullprüfen: Bei Tracking-Verlust kommt keine Pose zurück. Ohne Prüfung führt der Zugriff aufpose.viewszu einemTypeError. - Der Referenzraum muss zur selben Sitzung gehören wie der Frame. Außerdem muss sein Typ bei
requestSession()angefordert worden sein (z. B.optionalFeatures: ['local-floor']), sonst schlägtrequestReferenceSpace()fehl. - Rechne nicht mit einer festen Anzahl an Views. Durchlaufe immer
pose.views, denn Smartphone-AR hat einen View, Headsets haben zwei, und manche Geräte haben mehr. - Sichere Umgebung: WebXR funktioniert nur über HTTPS (oder localhost). In iframes braucht es die Permissions Policy
xr-spatial-tracking. - Kompatibilität: Unterstützt in Chromium-Browsern (Chrome, Edge, Samsung Internet), im Meta Quest Browser und in Safari auf visionOS. Firefox und Desktop-Safari unterstützen WebXR nicht. Prüfe vorher mit
navigator.xr?.isSessionSupported(). - Für die Pose anderer Objekte wie Controller oder Hände nimmst du
XRFrame.getPose().