Begrenzung der Framerate in Three.js zur Leistungssteigerung, requestAnimationFrame?

Lesezeit: 3 Minuten

Benutzer-Avatar
Cory Groß

Ich dachte, dass für einige Projekte, die ich mache, 60 fps nicht unbedingt erforderlich sind. Ich dachte mir, ich könnte mehr Objekte und Dinge haben, die mit 30 fps laufen, wenn ich es schaffe, dass es bei dieser Framerate reibungslos läuft. Ich dachte mir, wenn ich das RequestAnimationFrame-Shim innerhalb von three.js bearbeite, könnte ich es auf diese Weise auf 30 beschränken. Aber ich habe mich gefragt, ob es einen besseren Weg gibt, dies mit three.js selbst wie vorgesehen zu tun. Wird mir das auch die Art von Leistungssteigerung geben, die ich denke. Kann ich mit 30 fps doppelt so viele Objekte rendern wie mit 60? Ich kenne den Unterschied zwischen dem Laufenlassen von Dingen mit 30 und 60, aber werde ich in der Lage sein, es mit konstanten 30 fps zum Laufen zu bringen?

Ich verwende im Allgemeinen den WebGLRenderer und greife bei Bedarf auf Canvas zurück, außer bei Projekten, die speziell auf einen abzielen, und normalerweise sind dies WebGL-Shader-Projekte.

Was ist mit so etwas:

function animate() {

    setTimeout( function() {

        requestAnimationFrame( animate );

    }, 1000 / 30 );

    renderer.render();

}

Dieser Ansatz könnte auch funktionieren, indem die THREE.Clock verwendet wird, um das Delta zu messen.

let clock = new THREE.Clock();
let delta = 0;
// 30 fps
let interval = 1 / 30;

function update() {
  requestAnimationFrame(update);
  delta += clock.getDelta();

   if (delta  > interval) {
       // The draw or time dependent code are here
       render();

       delta = delta % interval;
   }
}

  • Dies funktioniert zumindest für mich besser als die akzeptierte Antwort. Meine Sprite-Animationen würden nach jeder Schleife für ein paar Millisekunden pausieren, wenn ich den setTimeout-Ansatz verwende. Dieser Vorschlag hat keinen solchen negativen Effekt, reduziert aber dennoch die CPU-Last gleichermaßen.

    – Johan Fredrik Varen

    22. November 2021 um 22:12 Uhr

  • Ich denke, so sollte man es machen, klug und sauber. Ich fühle mich auch nicht sehr wohl in Bezug auf den Speicher, wenn ich setTimeout mehrmals in einer Sekunde aufrufe. Es könnte völlig in Ordnung sein, aber immer noch.

    – aelmosalamy

    9. Januar um 0:35

  • Interessanterweise schlug mrdoob trotzdem setTimeout vor THREE.Clock gab es bereits 2012. Jedenfalls bin ich auch skeptisch gegenüber dem Timeout und diese Antwort ist solide!

    – Damien

    13. April um 15:00 Uhr

Die Menge an Arbeit, die Ihre CPU und GPU leisten müssen, hängt von der Arbeitslast ab und sie legen die Obergrenze für eine reibungslose Framerate fest.

  • Die GPU arbeitet größtenteils linear und kann immer die gleiche Anzahl von Polygonen auf den Bildschirm übertragen.

  • Wenn Sie jedoch die Anzahl der Objekte verdoppelt haben, muss die CPU härter arbeiten, um alle diese Objekte zu animieren (Matrixtransformationen und dergleichen). Es hängt von Ihrem Weltmodell und anderen Arbeiten ab, die Javascript erledigt, wie viel zusätzlicher Overhead gegeben ist. Auch die Bedingungen wie die Anzahl der sichtbar Objekte ist wichtig.

Für einfache Modelle, bei denen immer alle Polygone auf dem Bildschirm sind, sollte es ziemlich genau nach der Regel “halbe Framerate, doppelte Objekte” gehen. Für 3D-Shooter-ähnliche Szenen ist dies definitiv nicht der Fall.

Ich bin auf diesen Artikel gestoßen, der zwei Möglichkeiten zur Lösung des Problems mit der benutzerdefinierten Bildrate bietet.

http://codetheory.in/controlling-the-frame-rate-with-requestanimationframe/

Ich denke, dieser Weg ist robuster, da er auch auf Computern, die die Leinwand nicht konstant mit 60 fps rendern, eine konstante Animationsgeschwindigkeit hat. Unten ist ein Beispiel

var now,delta,then = Date.now();
var interval = 1000/30;

function animate() {
    requestAnimationFrame (animate);
    now = Date.now();
    delta = now - then;
    //update time dependent animations here at 30 fps
    if (delta > interval) {
        sphereMesh.quaternion.multiplyQuaternions(autoRotationQuaternion, sphereMesh.quaternion);
        then = now - (delta % interval);
    }
    render();
}

Benutzer-Avatar
Alexandria

Die akzeptierte Antwort hat ein Problem und gibt auf langsamen Computern bis zu -10 fps aus, verglichen mit der Nichtbegrenzung der fps, also beispielsweise ohne Begrenzung von 36 pfs, mit der akzeptierten Lösung 26 fps (für 60 fps, 1000/60 setTimeout).

Stattdessen können Sie Folgendes tun:

var dt=1000/60;
var timeTarget=0;
function render(){
  if(Date.now()>=timeTarget){

    gameLogic();
    renderer.render();

    timeTarget+=dt;
    if(Date.now()>=timeTarget){
      timeTarget=Date.now();
    }
  }
  requestAnimationFrame(render);
}

Dieser Weg wird nicht warten, wenn er bereits hinter sich hat.

1186590cookie-checkBegrenzung der Framerate in Three.js zur Leistungssteigerung, requestAnimationFrame?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy