我正在编写一些WebGL动画,但我无法使requestAnimationFrame工作得很流畅。我写了这个空循环来在不同的浏览器中测试它:
<html>
<body>
<script type="text/javascript">
var prev = Date.now();
function frame()
{
window.requestAnimationFrame(frame);
var now = Date.now();
var diff = now - prev;
prev = now;
if(diff > 20)
{
console.log(new Date().toLocaleTimeString() + ": " + diff);
}
}
frame();
</script>
</body>
</html>
如果超过20毫秒,它会计算帧和日志之间传递给控制台的时间。我的设置是:Windows 7 x64,Intel i7,Sapphire Tri-X R9 290,16 GB RAM。显示频率为60 Hz,因此我希望帧间的间隙为1/60 = 16.666(6)ms。所以我设置了20毫秒的阈值以防止控制台泛滥。一切都在背景中发生,一切都是空闲的。没有其他浏览器标签打开。这是我的数字:
Google Chrome:
7:47:13 AM: 53
7:47:16 AM: 53
7:47:19 AM: 53
7:47:22 AM: 53
7:47:25 AM: 54
7:47:28 AM: 53
7:47:31 AM: 53
7:47:34 AM: 53
7:47:37 AM: 54
7:47:40 AM: 54
7:47:43 AM: 54
7:47:46 AM: 54
7:47:49 AM: 55
7:47:52 AM: 54
7:47:55 AM: 54
你可以清楚地看到模式:每3秒53-55毫秒的差距。好的,试试另一个浏览器:
FireFox:
7:49:25: 53
7:49:25: 89
7:49:26: 88
7:49:28: 51
7:49:28: 42
7:49:28: 105
7:49:28: 52
7:49:28: 21
7:49:28: 29
7:49:34: 23
7:49:34: 22
7:49:38: 27
7:49:39: 55
7:49:39: 51
7:49:39: 108
7:49:45: 35
7:49:45: 43
7:49:45: 24
7:49:45: 103
7:50:09: 45
7:50:18: 22
7:50:19: 31
7:50:25: 59
7:50:25: 33
7:50:25: 21
更糟糕!好的,让我们继续吧。 Opera与Chrome一样具有相同的引擎,但令人惊讶的是它显示了几乎完美的时序,因此我将阈值降低到大于17毫秒:
Opera:
7:56:57 AM: 18
7:57:00 AM: 18
7:57:12 AM: 18
7:57:13 AM: 18
7:57:17 AM: 18
7:57:19 AM: 18
7:57:32 AM: 18
7:57:33 AM: 18
7:57:34 AM: 18
7:57:37 AM: 18
7:57:48 AM: 18
7:57:50 AM: 18
7:57:51 AM: 18
7:57:54 AM: 18
7:57:55 AM: 18
有趣的部分是它的功能几乎完美,直到你不触摸键盘和鼠标。如果移动鼠标光标,则可以写入此18 ms消息。而最大的惊喜 - IE11。在页面刷新后几秒钟消息后,它可以在不到1毫秒的精度下完全流畅地工作几分钟。干得好,IE11。
IE11:
7:59:25:18
7:59:25:18
那么,发生了什么?为什么这些行为如此不同?如何在所有浏览器中制作流畅的WebGL动画?
更新 我已将日志记录条件更改为:if(diff> 17 || diff&lt; 16)并且我发现Google Chrome和FireFox有时只有几毫秒的间隙,例如1-2-3毫秒。所以看起来他们正试图保持动画VSynced,但他们并没有做得很好。所以我的问题仍然存在。
答案 0 :(得分:1)
我在Chrome或Firefox中的MBP上看起来并不像你那么糟糕。事实上,我看到前1-3帧之后没有问题。
以下是您的示例内联。我改变了一点,使用传递给requestAnimationFrame
而不是Date.now
的时间,因为传递给requestAnimationFrame
的时间更准确。
我会注意到我已经打开了23个标签页,其中很多标签包括Stack Overflow本身在后台执行的操作,例如发送通知的websockets等。
PS:我认为你的意思是&#34;流畅的&#34;而不是&#34;流利&#34;?
var prev = 0;
var frameCount = 0;
function frame(now)
{
++frameCount;
var diff = now - prev;
prev = now;
if(diff > 20)
{
console.log(frameCount, new Date().toLocaleTimeString(), ": ", diff);
}
// It's easier to debug things with this at the bottom
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
&#13;