我正在创建一个 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 会更有优势。
想法?
最佳答案
有几个考虑因素:
javascript 中的
好吧,我实际上不确定最后一点,现在我考虑了一下。无论如何,我观察到了类似的问题,并且我设法制定了一个运行良好的解决方案,如果计算机完全可以处理这样的帧率,它将保持帧率平滑和 +/- 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;
};
您可以看到它根据最后一次调用(目标为 60FPS)调整 setTimeout。所以这是您可以尝试的一种解决方案。
我所做的(似乎运行良好的 hack)是将超时值作为变量,初始值为原始 33 或任何所需的帧速率。然后在每一帧上,我记录 Date.now(),并将其与前一帧时间进行比较。如果我们错过了预算的帧时间,我们将超时值减少 1。如果我们比预期的要快,我们将超时增加 1。因此代码会持续、平稳地调整超时以匹配所需的帧率。通过只稍微增加/减少,我们避免了不可预测的垃圾收集等问题,完全抛弃了计算和把事情搞砸了。它只是有效(tm)
我不会发布代码,因为我的渲染循环中有更多内容(如果某些内容发生更改,则仅渲染新帧等),隔离相关代码示例会很乏味。
关于performance - 通过 setInterval 限制 WebGL 帧率会严重降低性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18005674/