【问题标题】:Limiting WebGL Framerate via setInterval severely decreases performance通过 setInterval 限制 WebGL 帧率会严重降低性能
【发布时间】:2013-08-02 18:26:07
【问题描述】:

我正在创建一个 webgl 游戏,我对它进行了相当好的优化,但是有一个问题,我的帧率限制器破坏了性能。我知道你的想法“呃,当然是……它是一个 fps 限制器”。那么问题是它的行为没有达到预期。代码如下:

renderTimer = null;
function animate() {
  clearTimeout(renderTimer);
  renderTimer = setTimeout(function () {
    _frame = requestAnimationFrame(animate);
  }, 33);
  render();
}

function render(){
  // operations for mesh positioning/animation
  handleObjects();
  renderer.render(scene, camera);
}

在我的桌面上,它按预期工作,游戏流畅且保持在 29-30fps。

在我的笔记本电脑上 fps 下降到 22-24 并且游戏很生涩。如果我将间隔延迟更改为 16 毫秒,则游戏玩法相对流畅并保持在 35 fps 左右。如果我将所有时间间隔全部删除,则游戏完全流畅,并保持在 45fps 左右。

我不完全理解这种行为。如果上限是 30fps,为什么我的笔记本电脑性能会下降到 25fps 以下?我希望它在没有间隔的情况下也是 25fps,但它会更快。好奇。

我很乐意删除间隔,但我确实希望我的 fps 上限为 30,玩家获得更高的 fps 将具有优势。

想法?

【问题讨论】:

    标签: performance three.js webgl frame-rate


    【解决方案1】:

    有几个注意事项:

    • javascript 中的 setTimeout 不能说非常准确。
    • 浏览器可以随时做自己的事情,比如垃圾收集,延迟事情。
    • 渲染自身(webgl/three.js + 您自己的游戏逻辑)需要时间。即使您在主渲染调用之前创建了超时,它仍然会引入 33 毫秒的空闲时间。

    好吧,我实际上并不确定最后一点,现在我想了想。无论如何,我已经观察到类似的问题,并且我设法制作了一个运行良好的解决方案,如果计算机可以处理这样的帧率,它将保持帧率平滑和 +/- 1-2 FPS 精确到目标帧率。虽然这是一个 hack。

    首先你可以看看 Three.js 中的 requestAnimationFrame 实现(对于没有内置它的浏览器):

    requestAnimationFrame = function ( callback ) {
      var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
      var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall );
      lastTime = currTime + timeToCall;
      return id;
    };
    

    您可以看到它根据上次调用调整了 setTimeout(目标在 60FPS 左右)。所以这是您可以尝试的一种解决方案。

    我所做的(似乎运作良好的 hack)是将超时值作为变量,初始值为原始 33 或任何所需的帧速率。然后在每一帧上,我记录 Date.now(),并将其与前一帧时间进行比较。如果我们错过了预算的帧时间,我们将超时值减 1。如果我们的速度比预期的快,我们将超时值加 1。因此代码会持续、平滑地调整超时以匹配所需的帧速率。通过仅略微增加/减少,我们避免了不可预测的垃圾收集等问题,完全放弃了计算并搞砸了事情。它只是工作(tm)

    我不会发布代码,因为我的渲染循环还有很多事情要做(只有在发生更改时才渲染新帧等),隔离相关的代码示例会很乏味。

    【讨论】:

    • 有趣。因此,在您的示例中,您要覆盖现有的 requestAnimationFrame 函数?递增超时解决方案很有趣,当我下班时我得试一试。
    • 该 requestAnimationFrame 是 Three.js 中包含的 shim 的复制粘贴,以说明浏览器本身不支持它。这似乎是自动调整超时值的一个很好的例子。我描述的我的实现只是稍微扩展了这个想法(我没有覆盖 requestAnimationFrame,它都在 animate 函数和朋友中)。
    • 啊,好的,等不及要试一试=]
    • 可变目标率方法效果非常好,谢谢!
    • @yaku:我尝试使用您的方法,如果我想将 FPS 限制在 30 以下,它可以正常工作。如果说我想将 FPS 限制为 45,它似乎不起作用。事实上,只需在我的动画中添加一个 setTimeout(如下所示),将 FPS 降至 30。你能分享你的发现吗function animate(ts) { setTimeout(function () { requestAnimationFrame(animate); }, 1000/60); //Do the rendering }
    猜你喜欢
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    • 1970-01-01
    • 2021-03-26
    • 2013-12-16
    • 1970-01-01
    相关资源
    最近更新 更多