2013-05-08 3 views
1

Я пытаюсь сравнить производительность для 3d-приложений на мобильных устройствах. У меня есть 3D-солнечная система, созданная в webGL, и я пытаюсь записать или хотя бы отобразить FPS. До сих пор это то, что у меня есть:Запись FPS в webGL

в организме

<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 в функции жки холста у меня есть этот

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

выход я получаю на нижняя часть холста равна «fps равна нулю»

любая помощь была бы замечательной!

+1

взгляните на https://github.com/mrdoob/stats.js/ – gaitat

ответ

4

Я предполагаю, что вы вызываете 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> 
+3

никогда не используйте 'setInterval' для анимации. Это DoSes использует машину пользователя, когда вкладка скрыта. Используйте 'requestAnimationFrame'. См. Http://paulirish.com/2011/requestanimationframe-for-smart-animating/ – gman

+0

Спасибо, это именно то, что мне нужно! – tim

+0

Добро пожаловать! Посмотрите также на ответ @ gman и 'requestAnimationFrame', поскольку это лучший способ оживить материал. –

8

Отображение FPSS довольно прост и не имеет на самом деле ничего общего с 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>

0

Я создал объектно-ориентированный вариант ответа Bariş Uşaklı в. Он также отслеживает среднее значение fps за последнюю минуту.

Использование:

глобальная переменная:

var fpsCounter; 

Создать объект где-то при запуске программы:

fpsCounter = new FpsCounter(); 

Вызвать метод обновления в вашем розыгрыше() Funktion & обновление fps-дисплеи:

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

Примечание. Я просто добавляю обновления fps-display в функцию рисования для простоты. При 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); 
}; 
1

Поскольку ни один из других ответов не обращался к "в WebGL" часть вопроса, я буду добавьте следующие важные данные при правильном измерении FPS в WebGL.

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(), чтобы обеспечить правильное время измерения, поскольку все вызовы WebGL на GPU асинхронны!

Смежные вопросы