我正在尝试比较移动设备上的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”
任何帮助都会很棒!
答案 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元素:
<div id="fps">
&#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;