Start · Sprachen · JavaScript · Referenz · XRRigidTransform

XRRigidTransform

Schnittstelle

Beschreibt eine starre 3D-Transformation aus Position (<code>DOMPointReadOnly</code>) und Orientierung (Einheits-Quaternion) und liefert dazu die passende 4×4-Matrix und die inverse Transformation.

seit JavaScript WebXR Device API — Chromium-Browser (Chrome/Edge 7 Kategorie: webapi

Signatur

interface XRRigidTransform

Beschreibung

XRRigidTransform ist ein Baustein der WebXR Device API. Das Objekt steht für eine starre Transformation, also nur Verschiebung und Drehung, ohne Skalierung und ohne Scherung. Solche Transformationen beschreiben die Pose von Kopf, Controllern und Ankern und bilden das Verhältnis zwischen zwei Referenzräumen ab. Man findet sie zum Beispiel in XRPose.transform, XRView.transform und XRViewerPose.transform.

Mit dem Konstruktor new XRRigidTransform(position, orientation) legt man selbst eine Transformation an. Die häufigste Verwendung ist XRReferenceSpace.getOffsetReferenceSpace(): Damit verschiebt oder dreht man den Ursprung eines Referenzraums, etwa um den Spieler zu teleportieren oder die Blickrichtung per Controller-Stick zu drehen. Auch XRFrame.createAnchor() und Hit-Test-Anfragen erwarten ein XRRigidTransform.

Die Schnittstelle hat folgende Eigenschaften, die alle schreibgeschützt sind:

  • position: ein DOMPointReadOnly mit der Verschiebung in Metern (w ist immer 1).
  • orientation: ein DOMPointReadOnly mit einem normalisierten Quaternion (x, y, z, w).
  • matrix: ein Float32Array mit 16 Werten, eine 4×4-Matrix in spaltenweiser Anordnung (column-major). Sie lässt sich direkt an WebGL-Uniforms oder an Bibliotheken wie gl-matrix und three.js übergeben.
  • inverse: ein XRRigidTransform mit der umgekehrten Transformation. Die inverse Matrix der Betrachterpose ist zum Beispiel die View-Matrix für das Rendering.

Die Reihenfolge ist festgelegt: Zuerst wird gedreht, dann verschoben. Das ist wichtig, wenn man die Matrix mit eigenen Berechnungen vergleicht oder Transformationen hintereinander anwendet.

Parameter

Name Typ Default Beschreibung
$position DOMPointInit {x: 0, y: 0, z: 0, w: 1} Verschiebung in Metern. Fehlende Komponenten werden als 0 gesetzt, w muss 1 sein, sonst wird ein TypeError geworfen.
$orientation DOMPointInit {x: 0, y: 0, z: 0, w: 1} Drehung als Quaternion. Der Wert wird automatisch normalisiert. Ein Quaternion der Länge 0 ist ungültig und führt zu einem Fehler.

Rückgabewert

Typ
XRRigidTransform
Beschreibung
Ein neues, unveränderliches XRRigidTransform-Objekt mit den Eigenschaften position, orientation, matrix und inverse.

Beispiele

Transformation erzeugen und Eigenschaften lesen

// Um 90° um die Y-Achse drehen und 2 m nach vorn verschieben
const angle = Math.PI / 2;
const transform = new XRRigidTransform(
  { x: 0, y: 0, z: -2 },
  { x: 0, y: Math.sin(angle / 2), z: 0, w: Math.cos(angle / 2) }
);

console.log(transform.position.z);                 // Verschiebung
console.log(transform.orientation.w.toFixed(3));   // Quaternion-w
console.log(transform.matrix.length);              // 4×4-Matrix
console.log(transform.inverse.position.x.toFixed(3));
-2 0.707 16 2.000

Teleportation über einen verschobenen Referenzraum

let refSpace;

const startSession = async () => {
  const session = await navigator.xr.requestSession('immersive-vr');
  refSpace = await session.requestReferenceSpace('local-floor');
  return session;
};

// Spieler an die Zielposition (Weltkoordinaten) versetzen
const teleportTo = ({ x, z }) => {
  // Der Referenzraum wird umgekehrt verschoben, deshalb negative Werte
  const offset = new XRRigidTransform({ x: -x, y: 0, z: -z });
  refSpace = refSpace.getOffsetReferenceSpace(offset);
};

// Beispielaufruf nach Hit-Test auf dem Boden:
// teleportTo({ x: 3, z: -5 });

View- und Model-Matrizen für WebGL im Render-Loop

const onXRFrame = (time, frame) => {
  const session = frame.session;
  session.requestAnimationFrame(onXRFrame);

  const pose = frame.getViewerPose(refSpace);
  if (!pose) return; // Tracking verloren

  for (const view of pose.views) {
    // Die inverse Kamerapose ergibt die View-Matrix
    gl.uniformMatrix4fv(uViewMatrix, false, view.transform.inverse.matrix);
    gl.uniformMatrix4fv(uProjMatrix, false, view.projectionMatrix);
    drawScene();
  }

  // Controller-Pose als Model-Matrix verwenden
  for (const source of session.inputSources) {
    const gripPose = source.gripSpace && frame.getPose(source.gripSpace, refSpace);
    if (gripPose) {
      gl.uniformMatrix4fv(uModelMatrix, false, gripPose.transform.matrix);
      drawController();
    }
  }
};

Kontinuierliches Drehen per Controller-Stick (Snap-Turn)

// Um 30° nach rechts um den Kopf-Ursprung drehen
const snapTurn = (degrees) => {
  const rad = (-degrees * Math.PI) / 180;
  const rotation = new XRRigidTransform(
    undefined,
    { x: 0, y: Math.sin(rad / 2), z: 0, w: Math.cos(rad / 2) }
  );
  refSpace = refSpace.getOffsetReferenceSpace(rotation);
};

snapTurn(30);

// Wichtig · Fallstricke

  • Nur in sicheren Kontexten: Die Schnittstelle ist nur über HTTPS oder localhost verfügbar. In Firefox und Safari (Desktop) fehlt WebXR komplett. Vorher mit 'xr' in navigator und navigator.xr.isSessionSupported() prüfen.
  • Unveränderlich: position, orientation und matrix sind schreibgeschützt. Wer etwas ändern will, legt ein neues Objekt an. Das Überschreiben von Werten in matrix hat keine Wirkung auf die Transformation.
  • Richtung bei Offset-Räumen: getOffsetReferenceSpace() verschiebt den Ursprung des Raums. Damit sich der Nutzer an eine Zielposition bewegt, muss man meist mit negierten Werten oder mit inverse arbeiten. Das ist eine häufige Fehlerquelle.
  • Quaternion statt Euler-Winkel: Die Orientierung wird als Quaternion angegeben, nicht in Grad. Der Wert wird normalisiert, ein Null-Quaternion wirft aber einen Fehler. position.w muss 1 sein.
  • Matrix-Anordnung: matrix ist spaltenweise angeordnet (column-major), wie in WebGL. Bei zeilenweise arbeitenden Mathe-Bibliotheken muss man die Matrix transponieren.
  • Leistung: matrix und inverse werden verzögert berechnet und zwischengespeichert. Im Render-Loop ist es trotzdem sinnvoll, sie nur einmal pro Frame und Ansicht abzurufen und in einer Variablen zu halten.