Start · Sprachen · JavaScript · Referenz · VRDisplay.requestAnimationFrame()

VRDisplay.requestAnimationFrame()

Methode

Plant eine Rückruffunktion ein, die beim nächsten Frame des VR-Displays aufgerufen wird – mit der Bildwiederholrate des Headsets statt der des Monitors.

seit JavaScript WebVR 1.1 (veraltet, nicht standardisiert – durch deprecated seit ja Kategorie: webapi

Signatur

VRDisplay.prototype.requestAnimationFrame(callback)

Beschreibung

VRDisplay.requestAnimationFrame() ist die WebVR-Variante von Window.requestAnimationFrame(). Die übergebene Rückruffunktion wird aufgerufen, sobald das VR-Display bereit für ein neues Bild ist. Solange ein VRDisplay Inhalte präsentiert (isPresenting === true), läuft der Rückruf mit der nativen Bildwiederholrate des Headsets. Die liegt oft bei 90 Hz oder mehr und weicht damit von der Rate des Monitors ab.

Präsentiert das Display gerade nicht, verhält sich die Methode wie window.requestAnimationFrame(). Deshalb kann man eine einzige Render-Schleife schreiben, die sowohl im normalen Browserfenster als auch im VR-Modus funktioniert.

Wie beim Fenster-Gegenstück gilt die Planung nur für ein einziges Frame. Für eine dauerhafte Schleife muss die Rückruffunktion sich selbst erneut über vrDisplay.requestAnimationFrame() anmelden. Innerhalb des Rückrufs liest man typischerweise mit getFrameData() Pose und Matrizen aus, zeichnet die Szene für beide Augen und übergibt das Bild mit submitFrame() an das Headset.

Parameter

Name Typ Default Beschreibung
$callback Pflicht (timestamp: DOMHighResTimeStamp) => void Funktion, die beim nächsten Frame des VR-Displays aufgerufen wird. Sie erhält einen hochauflösenden Zeitstempel in Millisekunden.

Rückgabewert

Typ
number
Beschreibung
Eine ganzzahlige Handle-ID (größer als 0). Mit ihr lässt sich der Rückruf über VRDisplay.cancelAnimationFrame() wieder abbestellen.

Beispiele

Einfache VR-Render-Schleife

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const frameData = new VRFrameData();
let vrDisplay = null;

const drawScene = (projection, view) => {
  // Szene mit gegebener Projektions- und View-Matrix zeichnen
};

const onFrame = (timestamp) => {
  // Nächstes Frame direkt wieder anmelden
  vrDisplay.requestAnimationFrame(onFrame);

  vrDisplay.getFrameData(frameData);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  // Linkes Auge
  gl.viewport(0, 0, canvas.width / 2, canvas.height);
  drawScene(frameData.leftProjectionMatrix, frameData.leftViewMatrix);

  // Rechtes Auge
  gl.viewport(canvas.width / 2, 0, canvas.width / 2, canvas.height);
  drawScene(frameData.rightProjectionMatrix, frameData.rightViewMatrix);

  if (vrDisplay.isPresenting) {
    vrDisplay.submitFrame();
  }
};

if (navigator.getVRDisplays) {
  navigator.getVRDisplays().then((displays) => {
    if (displays.length > 0) {
      vrDisplay = displays[0];
      vrDisplay.requestAnimationFrame(onFrame);
    }
  });
} else {
  console.log('WebVR wird nicht unterstützt');
}

Schleife starten und wieder stoppen

let frameHandle = 0;

const loop = (timestamp) => {
  console.log(`Frame bei ${timestamp.toFixed(1)} ms`);
  frameHandle = vrDisplay.requestAnimationFrame(loop);
};

const startLoop = () => {
  frameHandle = vrDisplay.requestAnimationFrame(loop);
};

const stopLoop = () => {
  vrDisplay.cancelAnimationFrame(frameHandle);
  console.log('Render-Schleife gestoppt');
};

startLoop();
setTimeout(stopLoop, 1000);
Frame bei 16.7 ms Frame bei 27.8 ms ... Render-Schleife gestoppt

Fallback auf window.requestAnimationFrame

const getRaf = (display) =>
  display && typeof display.requestAnimationFrame === 'function'
    ? display.requestAnimationFrame.bind(display)
    : window.requestAnimationFrame.bind(window);

const raf = getRaf(window.vrDisplay);

const tick = (t) => {
  // Szene aktualisieren und zeichnen …
  raf(tick);
};

raf(tick);

// Wichtig · Fallstricke

Veraltet: Die gesamte WebVR-API ist obsolet und wurde aus allen gängigen Browsern entfernt: aus Firefox ab Version 98, Chrome hatte sie nur hinter einem Flag bzw. als Origin Trial. Für neue Projekte ist die WebXR Device API gedacht, dort mit XRSession.requestAnimationFrame(). Im Code sollte man die Verfügbarkeit immer mit navigator.getVRDisplays prüfen.

  • Während der Präsentation liefert nur vrDisplay.requestAnimationFrame() die richtige Taktung. Mit window.requestAnimationFrame() läuft die Schleife in der Rate des Monitors, und es kommt zu Rucklern oder Übelkeit.
  • Die Handle-IDs von VRDisplay und window sind nicht austauschbar. Zum Abbrechen daher immer cancelAnimationFrame() am selben Objekt aufrufen.
  • Nach exitPresent() fällt die Taktung wieder auf die Rate des Monitors zurück. Eine laufende Schleife läuft dann einfach weiter.
  • Die Rückruffunktion muss sich selbst neu anmelden, sonst wird sie nur einmal ausgeführt.