3

我正在尝试比较移动设备上 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”

任何帮助都会很棒!

4

5 回答 5

13

Displaying FPSs is pretty simple and has really nothing to do with WebGL other than it's common to want to know. Here's a small FPS display

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>

Use requestAnimationFrame for animation because that's what it's for. Browsers can sync to the screen refresh to give you buttery smooth animation. They can also stop processing if your page is not visible. setTimeout on the other hand is not designed for animation, will not be synchronised to the browser's page drawing.

You should probably not use Date.now() for computing FPS as Date.now() only returns milliseconds. Also using (new Date()).getTime() is especially bad since it's generating a new Date object every frame.

requestAnimationFrame already gets passed the time in microseconds since the page loaded so just use that.

It's also common to average the FPS across frames.

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>

于 2013-05-08T18:41:14.727 回答
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>
于 2013-05-08T04:48:04.100 回答
0

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

用法:

全局变量:

var fpsCounter;

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

 fpsCounter = new FpsCounter();

在您的 draw() 函数中调用更新方法并更新 fps 显示:

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

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

FPS计数器代码:

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;
};

覆盖缓冲区代码:

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);
};
于 2014-05-22T10:20:41.913 回答
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 调用都是异步的!

于 2017-02-07T12:40:52.403 回答
0

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

<div id="fps">

以下脚本可以解决问题:

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;
  }
}

于 2018-04-19T10:40:43.907 回答