如何解决requestAnimationFrame在不同浏览器上FPS不同的问题?
如何解决requestAnimationFrame
在不同浏览器上不同的FPS?
我正在使用 THREE.js
制作一个 3D 游戏,该游戏使用 requestAnimationFrame
,并且在 Google Chrome 15 上速度很快。
然而,它在 Firefox 6 上非常慢,在 IE9 上也非常慢(比 Firefox 慢)。
这确实是一个大问题,我想知道是否有解决方案。
谢谢。
How to solve different FPS in requestAnimationFrame
on different browsers?
I am making a 3D game using THREE.js
that uses requestAnimationFrame
and it is fast on Google Chrome 15.
However, it is really slow on Firefox 6 and really really slow (slower than Firefox) on IE9.
This is really a big problem and I am wondering if there is a solution to that.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Crafty 框架做了一些不同的事情,但可能适用于某些情况 - 每个游戏的滴答数绘制不是恒定的。相反,它会注意到帧速率何时落后于某个理想目标,并在执行绘制步骤之前循环多个游戏周期。你可以在github上看到step函数。
只要游戏能够顺利运行,这种方法就很有效。但如果你尝试一些处理器密集型的东西,它可能会加剧这种情况,因为它会优先考虑游戏逻辑而不是动画。
无论如何,只有当游戏逻辑和渲染逻辑某种程度上解耦时它才会起作用。 (如果它们完全解耦,您也许可以将它们放入完全独立的循环中。)
The Crafty framework does something that's a bit different, but might work for some cases -- the number of game ticks per draws is not constant. Rather, it notices when the framerate is falling behind some ideal target, and will cycle through multiple game ticks before performing the draw step. You can see the step function on github.
This works well so long as the game would be running smoothly. But if you try something more processor intensive, it can tend to exacerbate the situation, as it will prioritize game logic over animation.
In any case, it'll only work if the game logic and render logic are somewhat decoupled. (If they were completely decoupled you might be able to put them in completely separate loops.)
正如 adeneo 提到的,
requestAnimationFrame
回调会发送一个时间戳参数。以下是使用时间戳参数测量requestAnimationFrame
事件之间增量的解决方案,而不是使用Date()
函数创建单独的变量(其中performance.now( )
无论如何可能是一个更好的解决方案)。该解决方案还包括一个开始/停止选项,以展示为什么我在每次开始时使用单独的函数来初始化 previousTimestamp,以及为什么我要设置 reqID 值。
另请参阅 https://codepen.io/sassano/pen/wvgxxMp 了解另一个带有动画的示例这段代码就是从中衍生出来的。
As adeneo mentioned, the
requestAnimationFrame
callback is sent a timestamp argument. Here is a solution to measure the delta betweenrequestAnimationFrame
events using that timestamp argument instead of creating a separate variable using theDate()
function (whichperformance.now()
may be a better solution anyhow).This solution also includes a Start/Stop option to show why I am using a separate function to initialize the previousTimestamp at each start, and why I am setting a reqID value.
See also https://codepen.io/sassano/pen/wvgxxMp for another sample with animation from which this snippet was derived.
常见的做法是创建一个 deltaTime (dt) 变量,然后将其用作每个动画/更新周期的参数。
代码仅用于可视化问题/解决方案。
对于任何对渲染函数的调用,您都可以传递 dt
item.update(dt) 看起来像这样
The common thing to do is to create a deltaTime (dt) variable which is then be used as a parameter for every animation/update cycle.
Code is only for visualizing the problem/solution.
for any call to the render function you then pass dt
item.update(dt) looks like that
据我所知,除了减少代码的资源消耗之外,没有办法真正解决这个问题。
Chrome似乎是最快的浏览器,但通常FF也不甘落后,但IE仍然很慢。根据渲染方法(canvas、svg 或 webGL),它也非常依赖于本地硬件,因为它使用客户端来完成大多数操作,而复杂的 webGL 渲染需要强大的 GPU 才能实现良好的帧速率。
有多种方法可以动态测量帧速率,并相应地更改动画。
这是一个测量帧速率的非常简单的示例。
这只是一个即时测量,并不那么准确,您可能需要一些可以在一段时间内测量的东西,以便为所使用的浏览器获得更正确的帧速率。
另请注意
timestamp
参数,它在requestAnimationFrame
中是最小精度为 1 毫秒的高分辨率时间戳,也可用于确定动画的速度,并且任何浏览器延迟。As far as I know there's no way to really fix this, other than making your code less resource intensive.
Chrome seems to be the fastest browser, but usually FF is not far behind, but IE is still slow. Depending on the rendering methods, canvas, svg or webGL, it's also very dependent on your local hardware as it uses the clientside for most things, and complicated webGL renderings need a powerful GPU to achieve good framerates.
There are ways to measure the framerate on the fly, and change your animations accordingly.
Here's a very simple example that measures framerate.
This is just an instant measure that's not that accurate, you'd probably want something that measures over some time to get a more correct framerate for the browser being used.
Also note the
timestamp
argument, which inrequestAnimationFrame
is high-res timestamp with a minimal precision of 1 milliseconds, that can also be used to deterine the speed of the animation, and any browser lag.在某些浏览器上,requestAnimationFrame 的工作方式类似于
setTimeout(callback, 1000 / (16 + N)
,其中 N 是代码执行所需的时间。这意味着它会将 FPS 限制在 62Hz,但如果您的代码运行缓慢,它会限制在更低的范围内。当然,这并不适用于所有浏览器,并且将来可能会改变,但它仍然可以给你一个想法。它是如何工作的。
即使在每个浏览器中实现相同,也有许多因素会影响代码的性能等。您永远无法确定您的代码将以恒定的频率运行。
On some browsers requestAnimationFrame works something like
setTimeout(callback, 1000 / (16 + N)
where N is time required for your code to execute. Which means it caps your FPS at 62Hz but if your code works slowly, it will cap at something way lower. It basically tries to make a 16ms gap between every gap. Of course, this is not true for all browsers and will probably change in the future anyway but it still may give you an idea how it works.
Even if it was implemented the same in every browser, there are many factors which affect the performance of your code and etc. You can never be sure your code will be running at a constant frequency.