Расчет кадров в секунду в игре - PullRequest
102 голосов
/ 18 сентября 2008

Какой хороший алгоритм для расчета кадров в секунду в игре? Я хочу показать его в виде числа в углу экрана. Если я просто посмотрю на то, сколько времени понадобилось для рендеринга последнего кадра, число меняется слишком быстро.

Бонусные баллы, если ваш ответ обновляет каждый кадр и не сходится по-разному, когда частота кадров увеличивается или уменьшается.

Ответы [ 17 ]

1 голос
/ 18 сентября 2008

Вы можете сохранить счетчик, увеличивать его после рендеринга каждого кадра, а затем сбрасывать счетчик, когда вы находитесь в новую секунду (сохраняя предыдущее значение в качестве числа # отображаемых кадров в последнюю секунду)

0 голосов
/ 05 апреля 2017

Вот полный пример использования Python (но его легко адаптировать к любому языку). Он использует уравнение сглаживания в ответе Мартина, так что почти нет перегрузок памяти, и я выбрал значения, которые сработали для меня (не стесняйтесь поиграть с константами, чтобы приспособиться к вашему варианту использования).

import time

SMOOTHING_FACTOR = 0.99
MAX_FPS = 10000
avg_fps = -1
last_tick = time.time()

while True:
    # <Do your rendering work here...>

    current_tick = time.time()
    # Ensure we don't get crazy large frame rates, by capping to MAX_FPS
    current_fps = 1.0 / max(current_tick - last_tick, 1.0/MAX_FPS)
    last_tick = current_tick
    if avg_fps < 0:
        avg_fps = current_fps
    else:
        avg_fps = (avg_fps * SMOOTHING_FACTOR) + (current_fps * (1-SMOOTHING_FACTOR))
    print(avg_fps)
0 голосов
/ 18 сентября 2008

Установить счетчик на ноль. Каждый раз, когда вы рисуете кадр, увеличивайте счетчик. После каждой секунды печатать счетчик. вспенить, промыть, повторить. Если вам нужен дополнительный кредит, сохраняйте счетчик и делите его на общее количество секунд для скользящего среднего.

0 голосов
/ 18 мая 2013

Вот как я это делаю (на Java):

private static long ONE_SECOND = 1000000L * 1000L; //1 second is 1000ms which is 1000000ns

LinkedList<Long> frames = new LinkedList<>(); //List of frames within 1 second

public int calcFPS(){
    long time = System.nanoTime(); //Current time in nano seconds
    frames.add(time); //Add this frame to the list
    while(true){
        long f = frames.getFirst(); //Look at the first element in frames
        if(time - f > ONE_SECOND){ //If it was more than 1 second ago
            frames.remove(); //Remove it from the list of frames
        } else break;
        /*If it was within 1 second we know that all other frames in the list
         * are also within 1 second
        */
    }
    return frames.size(); //Return the size of the list
}
0 голосов
/ 06 января 2013
qx.Class.define('FpsCounter', {
    extend: qx.core.Object

    ,properties: {
    }

    ,events: {
    }

    ,construct: function(){
        this.base(arguments);
        this.restart();
    }

    ,statics: {
    }

    ,members: {        
        restart: function(){
            this.__frames = [];
        }



        ,addFrame: function(){
            this.__frames.push(new Date());
        }



        ,getFps: function(averageFrames){
            debugger;
            if(!averageFrames){
                averageFrames = 2;
            }
            var time = 0;
            var l = this.__frames.length;
            var i = averageFrames;
            while(i > 0){
                if(l - i - 1 >= 0){
                    time += this.__frames[l - i] - this.__frames[l - i - 1];
                }
                i--;
            }
            var fps = averageFrames / time * 1000;
            return fps;
        }
    }

});
0 голосов
/ 18 сентября 2008

хранить время запуска и увеличивать частоту кадров один раз за цикл? каждые несколько секунд вы можете просто напечатать framecount / (сейчас - время начала) и затем повторно инициализировать их.

редактировать: упс. двойной ninja'ed

0 голосов
/ 18 сентября 2008

В (c ++ like) псевдокоде эти два я использовал в промышленных приложениях для обработки изображений, которые должны были обрабатывать изображения с набора камер с внешним запуском. Изменения в «частоте кадров» имели другой источник (медленное или более быстрое производство на ленте), но проблема та же. (Я предполагаю, что у вас есть простой вызов timer.peek (), который дает вам что-то вроде nr msec (nsec?) С момента запуска приложения или последнего вызова)

Решение 1: быстро, но не обновляется каждый кадр

do while (1)
{
    ProcessImage(frame)
    if (frame.framenumber%poll_interval==0)
    {
        new_time=timer.peek()
        framerate=poll_interval/(new_time - last_time)
        last_time=new_time
    }
}

Решение 2: обновляется каждый кадр, требуется больше памяти и процессора

do while (1)
{
   ProcessImage(frame)
   new_time=timer.peek()
   delta=new_time - last_time
   last_time = new_time
   total_time += delta
   delta_history.push(delta)
   framerate= delta_history.length() / total_time
   while (delta_history.length() > avg_interval)
   {
      oldest_delta = delta_history.pop()
      total_time -= oldest_delta
   }
} 
...