如何使用requestAnimationFrame锁定FPS?

时间:2016-01-13 12:15:22

标签: html5 webgl frame requestanimationframe rate

我使用了Paul Irish的剧本 https://gist.github.com/paulirish/1579671 在html网站内创建动画循环。

虽然它在全屏模式下比在浏览器窗口中更快但它仍然有效。 此外,我根据画布大小和我使用的浏览器观察到不同的速度。

问题:如何使用脚本确保稳定的帧速率?

此处提供代码(由Web Danchilla开始WebGL,第1章): https://github.com/bdanchilla/beginningwebgl/blob/master/01/2D_movement.html

3 个答案:

答案 0 :(得分:2)

修饰@emackey所说的,

简短的回答是你不能。您可以要求计算机每帧执行无限量的工作。我不能保证在有限的时间内完成这项工作。

最重要的是,每台计算机都有不同的功率。廉价的集成GPU比高端显卡的功耗要低得多。 intel i3比i7慢得多。

您还提到了更改画布大小。绘制300x150画布的工作量仅为45000像素。绘制1920x1080画布将是2,073,600像素的工作或46倍的工作

您可以做的最好的事情是尽可能少地完成工作,或者自动或通过用户选择删除慢速硬件上的功能。大多数游戏都这样做。它们是图形设置选项,用户可以选择分辨率,纹理分辨率,反对等级和各种其他东西。

也就是说,您可以尝试进行计算,以便应用程序中的内容相对于时间以一致的速度移动。慢速机器或较大的画布上的帧速率可能较慢,但每秒移动的距离将保持不变。

您可以使用传递到requestAnimationFrame

的时间值来执行此操作
function render(time) {
   // time is time in milliseconds since the page was loaded

   ...do work...

   requestAnimationFrame(render);
}
requestAnimationFrame(render);

例如,这里是 NON 帧速率独立动画

function render(time) {

   xPosition = xPosition + velocity;

   ...

   requestAnimationFrame(render);
}
requestAnimationFrame(render);

这里是帧率独立动画

var then = 0;
function render(time) {
   var timeInSeconds = time * 0.001;
   var deltaTimeInSeconds = timeInSeconds - then;
   then = timeInSeconds;

   xPosition = xPosition + velocityInUnitsPerSecond * deltaTimeInSeconds;

   ...

   requestAnimationFrame(render);
}
requestAnimationFrame(render);

注意:传递到requestAnimationFrame的时间比Date.now()

更高

Here's an article on it with animations

答案 1 :(得分:1)

这样的事情应该有效。如果两帧之间的时间差小于FPS限制,则更新函数将返回并等待下一帧。但这只会限制更新发生得太快;就像emackey说的那样,更新循环总是有可能运行得更慢。

var updateId,
    previousDelta = 0,
    fpsLimit = 30;

function update(currentDelta) {
    updateId = requestAnimationFrame(update);

    var delta = currentDelta - previousDelta;

    if (fpsLimit && delta < 1000 / fpsLimit) {
        return;
    }

    /* your code here */

    previousDelta = currentDelta;
}

答案 2 :(得分:0)

您无法直接强制执行稳定的帧速率。您的页面不是用户平台上运行的唯一应用程序,平台功能差异很大。 requestAnimationFrame尽可能快地运行,不超过目标设备上的显示更新间隔,但可能会慢得多,具体取决于可用的CPU,GPU,内存和其他限制。

此处的标准做法是测量自上一个动画帧以来经过的时间量,通常使用Date.now(),并且每个帧将动画推进该时间量。对于人眼来说,这使得生成的动画以一致的速度运行,即使帧速率变化很大。

例如,ShadertoyGLSL Sandbox这样的网站会运行全屏GLSL着色器,并传入一个名为time(或iGlobalTime)的统一,这是一个{ {1}}表示自着色器启动以来经过的秒数。此时间值以不规则的间隔增加,具体取决于每个动画帧渲染的时间长度,但结果是浮动似乎以每秒1.0的稳定速度向上计数。通过这种方式,基于此时间值的着色器播放可以显示一致。