在webGL中录制FPS

时间:2013-05-08 04:41:51

标签: javascript webgl

我正在尝试比较移动设备上的3D应用程序的性能。我在webGL中设置了一个3d太阳能系统,我试图记录或至少显示FPS。到目前为止,这就是我所拥有的:

身体

<script language="javascript">
var x, message;
x = Time;
message = "fps is equal to ";
document.write (message); // prints the value of the message variable
document.write (x); //prints the value of x
</script>

并获得画布的绘制功能中的时间变量我有这个

var Time = 0;
function drawScene() {
var startTime = new Date();
//draw scene here
var endTime = new Date();
Time = (endTime - startTime)
}

我在画布底部得到的输出是“fps等于null”

任何帮助都会很棒!

5 个答案:

答案 0 :(得分:10)

显示FPS非常简单,除了通常想要了解之外,与WebGL无关。这是一个小型FPS显示器

const fpsElem = document.querySelector("#fps");

let then = 0;
function render(now) {
  now *= 0.001;                          // convert to seconds
  const deltaTime = now - then;          // compute time since last frame
  then = now;                            // remember time for next frame
  const fps = 1 / deltaTime;             // compute frames per second
  fpsElem.textContent = fps.toFixed(1);  // update fps display
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
<div>fps: <span id="fps"></span></div>

将requestAnimationFrame用于动画,因为它就是它的用途。浏览器可以同步到屏幕刷新,为您提供平滑的动画。如果您的页面不可见,他们也可以停止处理。另一方面,setTimeout不是为动画而设计的,不会同步到浏览器的页面绘图。

您可能不应该使用Date.now()来计算FPS,因为Date.now()仅返回毫秒。同样使用(new Date()).getTime()特别糟糕,因为它每帧都会生成一个新的Date对象。

自页面加载以来,

requestAnimationFrame已经以微秒为单位传递时间,所以只需使用它。

跨帧平均FPS也很常见。

const fpsElem = document.querySelector("#fps");
const avgElem = document.querySelector("#avg");

const frameTimes = [];
let   frameCursor = 0;
let   numFrames = 0;   
const maxFrames = 20;
let   totalFPS = 0;

let then = 0;
function render(now) {
  now *= 0.001;                          // convert to seconds
  const deltaTime = now - then;          // compute time since last frame
  then = now;                            // remember time for next frame
  const fps = 1 / deltaTime;             // compute frames per second
  
  fpsElem.textContent = fps.toFixed(1);  // update fps display
  
  // add the current fps and remove the oldest fps
  totalFPS += fps - (frameTimes[frameCursor] || 0);
  
  // record the newest fps
  frameTimes[frameCursor++] = fps;
  
  // needed so the first N frames, before we have maxFrames, is correct.
  numFrames = Math.max(numFrames, frameCursor);
  
  // wrap the cursor
  frameCursor %= maxFrames;
    
  const averageFPS = totalFPS / numFrames;

  avgElem.textContent = averageFPS.toFixed(1);  // update avg display
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { font-family: monospace; }
<div>        fps: <span id="fps"></span></div>
<div>average fps: <span id="avg"></span></div>

答案 1 :(得分:6)

我假设您反复调用drawScene,但如果您只设置x一次,则每次调用drawScene时都不会更新。此外,您在Time中存储的是经过时间而不是每秒帧数。

如下所示?我们的想法是计算渲染的帧数,并在fps变量中存储一秒后存储。

<script>
var elapsedTime = 0;
var frameCount = 0;
var lastTime = 0;

function drawScene() {

   // draw scene here

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

   frameCount++;
   elapsedTime += (now - lastTime);

   lastTime = now;

   if(elapsedTime >= 1000) {
       fps = frameCount;
       frameCount = 0;
       elapsedTime -= 1000;

       document.getElementById('test').innerHTML = fps;
   }
}

lastTime = new Date().getTime();
setInterval(drawScene,33);

</script>

<div id="test">
</div>

答案 2 :(得分:0)

我创建了一个面向对象版本的BarışUşaklı的答案。 它还跟踪最后一分钟的平均fps。

<强>用法:

全局变量:

var fpsCounter;

启动程序时在某处创建对象:

 fpsCounter = new FpsCounter();

在你的draw()funktion&amp;中调用更新方法。更新fps-displays:

function drawScene() {          
  fpsCounter.update();
  document.getElementById('fpsDisplay').innerHTML = fpsCounter.getCountPerSecond();
  document.getElementById('fpsMinuteDisplay').innerHTML = fpsCounter.getCountPerMinute();
  // Code   
}

注意:为了简单起见,我只将fps-display更新放在draw函数中。它以60fps的速度每秒设置60次,即使每秒一次就足够了。

FpsCounter代码:

function FpsCounter(){
    this.count = 0;
    this.fps = 0;
    this.prevSecond;  
    this.minuteBuffer = new OverrideRingBuffer(60);
}

FpsCounter.prototype.update = function(){
    if (!this.prevSecond) {     
        this.prevSecond = new Date().getTime();
            this.count = 1;
    }
    else {
        var currentTime = new Date().getTime();
        var difference = currentTime - this.prevSecond;
        if (difference > 1000) {      
            this.prevSecond = currentTime;
            this.fps = this.count; 
            this.minuteBuffer.push(this.count);
            this.count = 0;
        }
        else{
            this.count++;
        }
    }    
};

FpsCounter.prototype.getCountPerMinute = function(){
    return this.minuteBuffer.getAverage();
};

FpsCounter.prototype.getCountPerSecond = function(){
    return this.fps;
};

OverrideBuffer代码:

function OverrideRingBuffer(size){
    this.size = size;
    this.head = 0;
    this.buffer = new Array();
};

OverrideRingBuffer.prototype.push = function(value){      
    if(this.head >= this.size) this.head -= this.size;    
    this.buffer[this.head] = value;
    this.head++;
};

OverrideRingBuffer.prototype.getAverage = function(){
    if(this.buffer.length === 0) return 0;

    var sum = 0;    

    for(var i = 0; i < this.buffer.length; i++){
        sum += this.buffer[i];
    }    

    return (sum / this.buffer.length).toFixed(1);
};

答案 3 :(得分:0)

由于其他答案都没有解决问题中的“ in WebGL ”部分,因此在正确测量WebGL中的FPS时,我会添加以下重要细节。

window.console.time('custom-timer-id');    // start timer

/* webgl draw call here */                 // e.g., gl.drawElements();

gl.finish();                               // ensure the GPU is ready

window.console.timeEnd('custom-timer-id'); // end timer

为简单起见,我使用了控制台计时器。我正在努力指出始终使用WebGLRenderingContext.finish()来确保测量正确的时间,因为对GPU的所有WebGL调用都是异步的!

答案 4 :(得分:0)

使用旋转阵列可以做得更好。 与dom元素:

&#13;
&#13;
<div id="fps">
&#13;
&#13;
&#13;

以下脚本可以解决问题:

&#13;
&#13;
var fpsLastTick = new Date().getTime();
var fpsTri = [15, 15, 15]; // aims for 60fps

function animate() {
  // your rendering logic blahh blahh.....


  // update fps at last
  var now = new Date().getTime();
  var frameTime = (now - fpsLastTick);
  fpsTri.shift(); // drop one
  fpsTri.push(frameTime); // append one
  fpsLastTick = now;
  fps = Math.floor(3000 / (fpsTri[0] + fpsTri[1] + fpsTri[2])); // mean of 3
  var fpsElement = document.getElementById('fps')
  if (fpsElement) {
    fpsElement.innerHTML = fps;
  }
}
&#13;
&#13;
&#13;