通过setInterval限制WebGL帧率会严重降低性能

时间:2013-08-01 22:24:19

标签: performance three.js webgl frame-rate

我正在创建一个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,游戏玩法很生涩。如果我将间隔延迟更改为16ms,则游戏玩法相对平稳且保持在35fps左右。如果我删除间隔,所有游戏玩法都是完全平滑的并且保持在大约45fps。

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

我很高兴地删除了间隔,但是我希望我的fps上限为30,玩家获得更高的fps而不是优势。

思想?

1 个答案:

答案 0 :(得分:2)

有几点需要考虑:

  • javascript中的setTimeout无法真正计入非常准确。
  • 浏览器可以随时执行垃圾收集等任务,延迟使用。
  • 渲染自身(webgl / three.js +你自己的游戏逻辑)需要时间。即使您在主渲染调用之前创建了超时,它仍然会引入33毫秒的空闲时间。

好吧,我现在还不确定最后一点,现在我想起来了。无论如何,我已经观察到类似的问题,我设法制定了一个非常好的解决方案,如果计算机可以处理这样的帧速率,它将保持帧速率平滑并且+/- 1-2 FPS精确到目标帧速率。这是一个黑客。

首先,您可以查看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)。这是你可以尝试的一种解决方案。

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

我不会发布代码,因为我的渲染循环还有很多东西(只有在更改某些内容时才渲染新帧等),隔离相关代码示例会很繁琐。