HTML5 Canvas性能 - 计算每秒循环/帧数

时间:2011-02-22 13:45:03

标签: javascript html5 canvas frame-rate

我知道之前有一些问题像以前一样被提出过,例如:Check FPS in JS? - 这在某种程度上起了作用,我能够找出每个循环完成的时间。

我正在寻找的是更具可读性和可控性的东西。我希望能够设置FPS计数器的刷新率使其变慢,因此它是人类可读的或者应用程序可以运行的速度,因此我可以在某种速度计上使用它。

无论如何,这就是我现在的代码:

var lastLoop = new Date().getTime();

function updateStage()
{   
    clearCanvas();
    updateStageObjects();
    drawStageObjects();     

    var thisLoop = new Date().getTime(); 
    var fps = (thisLoop - lastLoop);

    $('#details').html(fps);

    lastLoop = thisLoop;
    iteration = setTimeout(updateStage, 1);
}
  1. 我是否正确将setTimeout函数设置为1毫秒的速度?我以为这会让它尽可能快地循环。

  2. 我应该每隔100帧计算一次,找出运行100帧所花费的毫秒数,然后进行计算以找出毫秒数为1000时应该完成的帧数?这个计算是什么?

  3. 为了让结果更准确,我猜我需要显示平均值,因为一帧可以变化很大,我应该怎么做?

  4. 非常感谢任何提示。

    感谢。

5 个答案:

答案 0 :(得分:23)

  1. 请注意,更新输出的速度越快,对测量的影响就越大。虽然很小,但我尝试每秒更新一次fps输出或更少,除非有必要加快速度。

  2. 我喜欢对我的结果进行低通滤波,以便临时打嗝不会太强烈地影响值。这比移动平均值更容易计算和写入,并且没有总体平均值的问题,即“当前”读数会受到整个运行期间总体性能的影响(例如,启动期间的异常读数)。

  3. 总之,这是我通常测量FPS的方式:

    var fps = 0, now, lastUpdate = (new Date)*1;
    
    // The higher this value, the less the FPS will be affected by quick changes
    // Setting this to 1 will show you the FPS of the last sampled frame only
    var fpsFilter = 50;
    
    function drawFrame(){
      // ... draw the frame ...
    
      var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
      if (now!=lastUpdate){
        fps += (thisFrameFPS - fps) / fpsFilter;
        lastUpdate = now;
      }
    
      setTimeout( drawFrame, 1 );
    }
    
    var fpsOut = document.getElementById('fps');
    setInterval(function(){
      fpsOut.innerHTML = fps.toFixed(1) + "fps";
    }, 1000); 
    

答案 1 :(得分:3)

我尝试了一些东西,

如果您更改

lastUpdate = now

lastUpdate = now * 1 - 1;

你的NaN问题已经解决了!这也适用于定义lastUpdate的地方。可能是因为它无法将日期转换为unix时间戳。

新结果将是:

var fps = 0, now, lastUpdate = (new Date)*1 - 1;

// The higher this value, the less the FPS will be affected by quick changes
// Setting this to 1 will show you the FPS of the last sampled frame only
var fpsFilter = 50;

function drawFrame(){
  // ... draw the frame ...

  var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
  fps += (thisFrameFPS - fps) / fpsFilter;
  lastUpdate = now * 1 - 1;

  setTimeout( drawFrame, 1 );
}

var fpsOut = document.getElementById('fps');
setInterval(function(){
  fpsOut.innerHTML = fps.toFixed(1) + "fps";
}, 1000); 

答案 2 :(得分:2)

我已经发布了解决方案并对其进行了一些改进。看看这里 - http://jsfiddle.net/ync3S/

  1. 我通过使用Date.now()修复了NaN错误,而不是每次都构造一个新的日期对象并尝试引用它。这也可以防止一些垃圾收集的必要性。
  2. 我把变量和函数名称加了一些,并添加了一些额外的评论 - 没必要,但很高兴。
  3. 我提供了一些用于测试的绘图代码。
  4. 我添加了fpsDesired作为引擎循环的测试变量。
  5. 我在fpsDesired上启动了fpsAverage,所以使用fpsFilter它不会从0到真正的FPS,而是从所需的FPS开始并从那里进行调整。
  6. 现在绘制块已经绘制了,这可以用于暂停和其他控制功能。
  7. 主要栏目如下:

    var fpsFilter = 1; // the low pass filter to apply to the FPS average
    var fpsDesired = 25; // your desired FPS, also works as a max
    var fpsAverage = fpsDesired;
    var timeCurrent, timeLast = Date.now();
    var drawing = false;
    
    function fpsUpdate() {
        fpsOutput.innerHTML = fpsAverage.toFixed(2);
    }
    
    function frameDraw() {
        if(drawing) { return; } else { drawing = true; }
    
        timeCurrent = Date.now();
        var fpsThisFrame = 1000 / (timeCurrent - timeLast);
        if(timeCurrent > timeLast) {
            fpsAverage += (fpsThisFrame - fpsAverage) / fpsFilter;
            timeLast = timeCurrent;
        }
    
        drawing = false;
    }
    
    setInterval(fpsUpdate, 1000);
    fpsUpdate();
    
    setInterval(frameDraw, 1000 / fpsDesired);
    frameDraw();
    

    要修补一下,看看我能否提出更顺畅的东西,因为这个帖子在谷歌搜索结果中接近顶部。

    让我们看看我们作为一个团队能够提出什么,而且我认为不使用第三方库总是很好,使得代码可以移植给所有人:)

    -Platima

答案 3 :(得分:1)

只需设置一个每秒重置fps计数器的间隔。

var fpsOut, fpsCount;

var draw = function () {

    fpsCount++;

    ..Draw To Canvas..


    ..Get the fps value: fpsOut

    requestAnimationFrame(draw);

};
setInterval(function () {

    fpsOut = fpsCount;
    fpsCount = 0;

}, 1000);

draw();

答案 4 :(得分:0)

如果要实时更新,请考虑使其一次又一次地实时循环。为了使其对性能的影响较小,仅更新受控变量,在这种情况下为FPS。为了以防万一,您可以选择可选的“帧延迟”,我将在此处放置。只需复制,粘贴和调整代码即可满足您的需求。

请注意,单个帧持续16.66毫秒。

setInterval(function(){var latencybase1 = parseFloat(new Date().getTime());
var latencybase2 = parseFloat(new Date().getTime());
var latency = latencybase2-latencybase1;
var fps = Math.round(1000/latency);

if (latency<16.66) 
{document.getElementById("FPS").innerHTML = fps+" 
FPS";}
else {document.getElementById("FPS").innerHTML = ""+fps+" FPS";}
document.getElementById("Latency").innerHTML = latency+" ms";}, 0);