Signatur
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
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);
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. Mitwindow.requestAnimationFrame()läuft die Schleife in der Rate des Monitors, und es kommt zu Rucklern oder Übelkeit. - Die Handle-IDs von
VRDisplayundwindowsind nicht austauschbar. Zum Abbrechen daher immercancelAnimationFrame()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.