Javascript 在webGL中记录FPS

Javascript 在webGL中记录FPS,javascript,webgl,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

我试图比较移动设备上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>
我在画布底部得到的输出是“fps等于null”


任何帮助都会很好

我假设您反复调用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>

var elapsedTime=0;
var frameCount=0;
var lastTime=0;
函数drawsecene(){
//在这里画场景
var now=new Date().getTime();
frameCount++;
elapsedTime+=(现在-上次);
上次=现在;
如果(elapsedTime>=1000){
fps=帧数;
帧数=0;
elapsedTime-=1000;
document.getElementById('test').innerHTML=fps;
}
}
lastTime=新日期().getTime();
设置间隔(drawScene,33);

显示FPS非常简单,实际上与WebGL没有任何关系,只是大家都想知道。这是一个小的FPS显示

const fpsElem=document.querySelector(“#fps”);
然后设=0;
函数渲染(现在){
现在*=0.001;//转换为秒
const deltaTime=now-then;//计算自上一帧起的时间
然后=现在;//记住下一帧的时间
常量fps=1/deltaTime;//每秒计算帧数
fpsElem.textContent=fps.toFixed(1);//更新fps显示
请求动画帧(渲染);
}
请求动画帧(渲染)

fps:
我创建了BarıUşaklı答案的面向对象版本。 它还跟踪最后一分钟的平均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);
};
全局变量:

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

 fpsCounter = new FpsCounter();
在draw()函数中调用update方法并更新fps显示:

function drawScene() {          
  fpsCounter.update();
  document.getElementById('fpsDisplay').innerHTML = fpsCounter.getCountPerSecond();
  document.getElementById('fpsMinuteDisplay').innerHTML = fpsCounter.getCountPerMinute();
  // Code   
}
注意:为了简单起见,我只将fps显示更新放在draw函数中。在每秒60帧的情况下,它会被设置为每秒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);
};
函数重写缓冲区(大小){
这个。大小=大小;
这个头=0;
this.buffer=新数组();
};
overrideeringbuffer.prototype.push=函数(值){
如果(this.head>=this.size)this.head-=this.size;
this.buffer[this.head]=值;
这个.head++;
};
overrideeringbuffer.prototype.getAverage=函数(){
如果(this.buffer.length==0)返回0;
var总和=0;
for(var i=0;i
由于其他答案均未提及问题的“在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

为了简单起见,我使用了控制台计时器。我试图指出始终使用的要点,以确保测量正确的时间,因为所有对GPU的WebGL调用都是异步的

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


切勿将
setInterval
用于动画。当选项卡被隐藏时,它将使用用户的机器。使用
requestAnimationFrame
。看,谢谢这正是我需要的!不客气!再看看@gman的答案,然后
requestAnimationFrame
,因为这是制作动画的更好方法be
elapsedTime=0?在我做出更改之前,我无法实现这一点。请看一看,虽然您的大多数答案都很好,但有一点很重要:1除以帧时间(
deltaTime
)不是计算每秒帧数的正确方法。你应该在一秒钟内计算渲染的帧数,就像在接受的答案中一样。如果一帧用了.9秒,59帧用了0.00169秒,你不会看到,如果你所做的只是看一秒钟内绘制的帧数,你当然会看到。帧时间为0.00169s时,应用程序以600 FPS的速度渲染。所以,如果一帧现在需要0.9秒,那么帧计数器将计数60帧,而不是600帧,所以您将看到10倍的差异。帧计数类似于您的
averageFPS
,但变量更少,代码更简单
只是一个一厢情愿的想法,如果所有帧都能在那一时间渲染,我们可以拥有多少FPS。顺便说一句,WebGL基础知识太棒了!:)这行不通<代码>总帐。在WebGL中完成
不会按照您的想法执行。即使在OpenGL中,这也不会给出准确的结果