Start · Sprachen · JavaScript · Referenz · XRView.projectionMatrix

XRView.projectionMatrix

Eigenschaft

Liefert die 4×4-Projektionsmatrix (<code>Float32Array</code>) einer <code>XRView</code>, mit der Szenenkoordinaten für genau diese Ansicht (z. B. ein Auge) auf den Bildschirm projiziert werden.

seit JavaScript WebXR Device API (Chrome/Edge 79+, Samsung Interne Kategorie: webapi

Signatur

XRView.projectionMatrix

Beschreibung

Die schreibgeschützte Eigenschaft projectionMatrix der Schnittstelle XRView gibt die Projektionsmatrix zurück, die für die jeweilige Ansicht verwendet werden muss. Es handelt sich um ein Float32Array mit 16 Werten in spaltenweiser Anordnung (column-major). Das Format passt direkt zu WebGL-Funktionen wie gl.uniformMatrix4fv() und zu Bibliotheken wie gl-matrix oder three.js.

Die Matrix beschreibt Sichtfeld (field of view), Seitenverhältnis sowie die Near- und Far-Clipping-Ebenen der Ansicht. Bei VR-Headsets ist sie meist asymmetrisch (off-axis), weil jedes Auge einen anderen Frustum hat. Deshalb sollte man sie nie selbst berechnen (etwa mit mat4.perspective()), sondern immer den vom Gerät gelieferten Wert verwenden. Sonst entstehen Verzerrungen, Doppelbilder und im schlimmsten Fall Übelkeit beim Nutzer.

Man verwendet die Eigenschaft in jedem Frame innerhalb des Callbacks von XRSession.requestAnimationFrame(). Dort liefert XRFrame.getViewerPose() ein XRViewerPose-Objekt, dessen Array views für jede Ansicht ein XRView enthält. Die Projektionsmatrix wird zusammen mit der View-Matrix (view.transform.inverse.matrix) an den Shader übergeben.

Die Near- und Far-Werte der Matrix richten sich nach XRRenderState.depthNear und depthFar. Diese lassen sich über XRSession.updateRenderState() ändern. Die Matrix kann sich deshalb von Frame zu Frame ändern.

Rückgabewert

Typ
Float32Array
Beschreibung
Ein Float32Array mit 16 Elementen: eine 4×4-Projektionsmatrix in spaltenweiser Anordnung für die jeweilige Ansicht. Ist die Ansicht ungültig, wird beim Zugriff eine InvalidStateError-Exception geworfen.

Beispiele

Projektionsmatrix pro Auge an einen WebGL-Shader übergeben

// Voraussetzung: session, refSpace, gl, program und glLayer sind bereits eingerichtet
const uProjection = gl.getUniformLocation(program, 'uProjectionMatrix');
const uView = gl.getUniformLocation(program, 'uViewMatrix');

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

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

  const glLayer = session.renderState.baseLayer;
  gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  for (const view of pose.views) {
    const vp = glLayer.getViewport(view);
    gl.viewport(vp.x, vp.y, vp.width, vp.height);

    // Direkt verwendbar, da column-major Float32Array
    gl.uniformMatrix4fv(uProjection, false, view.projectionMatrix);
    gl.uniformMatrix4fv(uView, false, view.transform.inverse.matrix);

    drawScene();
  }
};

session.requestAnimationFrame(onXRFrame);

Matrix inspizieren und Near/Far-Ebene zurückrechnen

const logProjection = (view) => {
  const m = view.projectionMatrix;
  console.log(view.eye, m.length);

  // Für eine Standard-Perspektivmatrix: m[10] = (f+n)/(n-f), m[14] = 2fn/(n-f)
  const near = m[14] / (m[10] - 1);
  const far = m[14] / (m[10] + 1);
  console.log(`near=${near.toFixed(2)} far=${far.toFixed(2)}`);
};

session.requestAnimationFrame((t, frame) => {
  const pose = frame.getViewerPose(refSpace);
  pose?.views.forEach(logProjection);
});
left 16 near=0.10 far=1000.00 right 16 near=0.10 far=1000.00

Clipping-Ebenen ändern und Matrix mit three.js nutzen

import * as THREE from 'three';

// Near/Far beeinflussen die gelieferte projectionMatrix
await session.updateRenderState({ depthNear: 0.05, depthFar: 500 });

const camera = new THREE.PerspectiveCamera();

const applyView = (view) => {
  camera.projectionMatrix.fromArray(view.projectionMatrix);
  camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();
  camera.matrixWorld.fromArray(view.transform.matrix);
  camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
};

// Wichtig · Fallstricke

  • Nicht selbst berechnen: Die Matrizen der Headsets sind oft asymmetrisch. mat4.perspective() oder ein festes Sichtfeld führen zu fehlerhafter Stereodarstellung.
  • Pro Frame neu lesen: Die Matrix kann sich ändern, zum Beispiel nach updateRenderState() oder bei Kalibrierung des Geräts. Deshalb weder zwischenspeichern noch über mehrere Frames wiederverwenden.
  • Nur im gültigen Frame: XRView-Objekte sind nur während des zugehörigen requestAnimationFrame-Callbacks aktiv. Ein späterer Zugriff kann eine InvalidStateError-Exception auslösen.
  • Spaltenweise Anordnung: Beim Übergeben an WebGL transpose auf false setzen. In DirectX-artigen Mathematikbibliotheken ist gegebenenfalls eine Transposition nötig.
  • Kompatibilität: WebXR erfordert einen sicheren Kontext (HTTPS). Unterstützt wird es in Chromium-Browsern (Chrome, Edge, Samsung Internet, Meta Quest Browser). Firefox und Safari auf dem Desktop unterstützen die API nicht, Safari auf der Apple Vision Pro nur eingeschränkt. Die Verfügbarkeit per navigator.xr?.isSessionSupported() prüfen.