Signatur
Beschreibung
Die Eigenschaft linearVelocity eines XRPose-Objekts gibt an, wie schnell und in welche Richtung sich der verfolgte Punkt gerade bewegt, also etwa ein Controller, eine Hand oder der Kopf des Nutzers. Der Wert ist ein DOMPointReadOnly. Die Komponenten x, y und z bilden den Geschwindigkeitsvektor in Metern pro Sekunde, w ist immer 0.
Der Vektor bezieht sich auf das Koordinatensystem des Basis-Raums. Das ist der XRSpace, den man als zweites Argument an XRFrame.getPose() oder XRFrame.getViewerPose() übergibt, meist ein XRReferenceSpace vom Typ "local" oder "local-floor".
Typische Einsatzfälle sind das Werfen virtueller Objekte, bei dem die Geschwindigkeit beim Loslassen direkt übernommen wird, sowie Gestenerkennung (z. B. „Schlag“ oder „Wischen“) und eine flüssigere Darstellung, wenn Posen vorausberechnet werden. Liefert das Gerät keine Geschwindigkeitsdaten, ist der Wert null. Deshalb sollte man immer eine eigene Berechnung aus den Positionsunterschieden zwischen zwei Frames als Ersatz vorsehen.
Rückgabewert
x, y, z; w = 0) relativ zum Basis-Raum, oder null, wenn das Gerät keine Geschwindigkeit liefern kann.Beispiele
Controller-Geschwindigkeit im Frame-Loop auslesen
const session = await navigator.xr.requestSession('immersive-vr');
const refSpace = await session.requestReferenceSpace('local-floor');
const onFrame = (time, frame) => {
for (const source of frame.session.inputSources) {
const pose = frame.getPose(source.gripSpace ?? source.targetRaySpace, refSpace);
const v = pose?.linearVelocity;
if (v) {
const speed = Math.hypot(v.x, v.y, v.z);
console.log(`${source.handedness}: ${speed.toFixed(2)} m/s`);
}
}
frame.session.requestAnimationFrame(onFrame);
};
session.requestAnimationFrame(onFrame);
Objekt werfen – Geschwindigkeit beim Loslassen übernehmen
let latestFrame = null;
const ball = { position: [0, 1, 0], velocity: [0, 0, 0], held: true };
session.requestAnimationFrame(function loop(t, frame) {
latestFrame = frame;
frame.session.requestAnimationFrame(loop);
});
session.addEventListener('selectend', (event) => {
// event.frame ist nur während des Event-Handlers gültig
const pose = event.frame.getPose(event.inputSource.gripSpace, refSpace);
if (!pose) return;
const v = pose.linearVelocity;
ball.held = false;
ball.velocity = v ? [v.x, v.y, v.z] : [0, 0, 0];
console.log('Wurfgeschwindigkeit:', ball.velocity.map((n) => n.toFixed(2)));
});
Ersatzberechnung, wenn linearVelocity null ist
let lastPos = null;
let lastTime = null;
const getVelocity = (pose, time) => {
if (pose.linearVelocity) {
const { x, y, z } = pose.linearVelocity;
return { x, y, z };
}
// Ersatz: Positionsdifferenz / Zeitdifferenz
const p = pose.transform.position;
let v = { x: 0, y: 0, z: 0 };
if (lastPos && time > lastTime) {
const dt = (time - lastTime) / 1000; // ms -> s
v = { x: (p.x - lastPos.x) / dt, y: (p.y - lastPos.y) / dt, z: (p.z - lastPos.z) / dt };
}
lastPos = { x: p.x, y: p.y, z: p.z };
lastTime = time;
return v;
};
// Wichtig · Fallstricke
- Kann
nullsein: Viele Geräte und Browser liefern keine Geschwindigkeit. Prüfe den Wert vor jedem Zugriff und rechne gegebenenfalls selbst aus Positionen und Zeitstempeln. - Bezugssystem: Der Vektor gilt im Basis-Raum, der an
getPose()übergeben wurde, und nicht im lokalen Raum des Objekts. Wechselst du den Referenzraum, ändert sich auch der Vektor. - Einheit: Die Werte sind in m/s angegeben und nicht pro Frame. Für eine Physik-Simulation musst du sie mit der Zeitdifferenz des Frames in Sekunden multiplizieren.
- Gültigkeit:
XRFrame-Objekte sind nur innerhalb ihres Callbacks bzw. Event-Handlers aktiv. Werte, die du später brauchst, solltest du kopieren ({ x, y, z }), statt das Objekt selbst zu speichern. - Kompatibilität: Die Eigenschaft ist experimentell und hat keinen Baseline-Status. Sie funktioniert nur in sicheren Kontexten (HTTPS) und während einer aktiven WebXR-Sitzung. Firefox und Safari unterstützen sie nicht oder nur eingeschränkt.