Javascript 限制 Three.js 中的帧率以提高性能,requestAnimationFrame?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11285065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 05:17:13  来源:igfitidea点击:

Limiting framerate in Three.js to increase performance, requestAnimationFrame?

javascripthtmlcanvasthree.jsrequestanimationframe

提问by Cory Gross

I was thinking that for some projects I do 60fps is not totally needed. I figured I could have more objects and things that ran at 30fps if I could get it to run smoothly at that framerate. I figured if I edited the requestAnimationFrame shim inside of three.js I could limit it to 30 that way. But I was wondering if there was a better way to do this using three.js itself as provided. Also, will this give me the kind of performance increase I am thinking. Will I be able to render twice as many objects at 30fps as I will at 60? I know the difference between running things at 30 and 60, but will I be able to get it to run at a smooth constant 30fps?

我在想,对于某些项目,我并不完全需要 60fps。我想如果我能让它以该帧速率平稳运行,我可以拥有更多以 30fps 运行的对象和事物。我想如果我在 Three.js 中编辑 requestAnimationFrame shim,我可以将它限制为 30。但是我想知道是否有更好的方法来使用提供的three.js本身来做到这一点。此外,这是否会给我带来我所想的那种性能提升。我能以 30fps 的速度渲染两倍于 60 帧的对象吗?我知道以 30 和 60 的速度运行东西之间的区别,但是我能否让它以稳定的 30fps 速度运行?

I generally use the WebGLRenderer, and fall back to Canvas if needed except for projects that are targeting one specifically, and typically those are webgl shader projects.

我通常使用 WebGLRenderer,并在需要时回退到 Canvas,除了专门针对某个项目的项目,通常这些项目是 webgl 着色器项目。

回答by mrdoob

What about something like this:

这样的事情怎么样:

function animate() {

    setTimeout( function() {

        requestAnimationFrame( animate );

    }, 1000 / 30 );

    renderer.render();

}

回答by Mikko Ohtamaa

The amount of work your CPU and GPU needs to do depend on the workload and they set the upper limit of smooth framerate.

你的 CPU 和 GPU 需要做的工作量取决于工作负载,它们设置了平滑帧率的上限。

  • GPU works mostly linearly and can always push out the same count of polygons to screen.

  • However, if you have doubled the number of objects CPU must work harder to animate these all objects (matrix transformationsn and such). It depends on your world model and other work Javascript does how much extra overhead is given. Also the conditions like the number of visibleobjects is important.

  • GPU 主要是线性工作的,并且总是可以将相同数量的多边形推出到屏幕上。

  • 但是,如果对象数量增加一倍,CPU 必须更加努力地为这些所有对象(矩阵变换等)设置动画。这取决于你的世界模型和其他工作 Javascript 做了多少额外的开销。可见对象的数量等条件也很重要。

For simple models where all polygons are on the screen always then it should pretty much follow the rule "half the framerate, double the objects". For 3D shooter like scenes this is definitely not the case.

对于所有多边形总是在屏幕上的简单模型,它应该几乎遵循“帧率减半,对象加倍”的规则。对于类似 3D 射击游戏的场景来说,情况绝对不是这样。

回答by karlos

This approach could also work, using the THREE.Clock to measure the delta.

这种方法也可以使用 THREE.Clock 来测量增量。

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;
   }
}

回答by Elder Snayz

I came across this article which gives two ways of solving the custom frame rate issue.

我遇到了这篇文章,它提供了两种解决自定义帧速率问题的方法。

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

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

I think this way is more robust, as it will have a steady animation speed even on computers that do not render the canvas consistently at 60 fps. Below is an example

我认为这种方式更健壮,因为即使在不能以 60 fps 始终如一地渲染画布的计算机上,它也将具有稳定的动画速度。下面是一个例子

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();
}

回答by Alexandria

The accepted answer has a problem and gives up to -10fps on slow computers compared to not limiting the fps, so for example without limiting 36pfs, with the accepted solution 26fps (for a 60fps, 1000/60 setTimeout).

接受的答案有问题,与不限制 fps 相比,在慢速计算机上最多可提供 -10fps,因此例如不限制 36pfs,接受的解决方案为 26fps(对于 60fps,1000/60 setTimeout)。

Instead you can do this:

相反,您可以这样做:

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);
}

That way is not going to wait if its already behind.

如果它已经落后,那么这种方式不会等待。