Я не могу понять, почему этот счетчик кадров в секунду является неточным - PullRequest
2 голосов
/ 14 февраля 2010

Я пытаюсь отслеживать кадры в секунду в моей игре. Я не хочу, чтобы fps показывал в среднем. Я хочу посмотреть, как влияет частота кадров, когда я нажимаю клавиши, добавляю модели и т. Д. Поэтому я использую переменную для хранения текущего и предыдущего времени, и когда они отличаются на 1 секунду, я обновляю fps.

Моя проблема в том, что он показывает скорость около 33 кадров в секунду, но когда я очень быстро перемещаю мышь, частота кадров увеличивается до 49 кадров в секунду. В других случаях, если я изменю простую строку кода в другом месте, не относящемся к счетчику кадров, или закрою проект и открою его позже, fps будет около 60. Vsync включен, поэтому я не могу сказать, продолжает ли работать мышь fps.

Вот мой код, который находится в функции обновления, которая происходит каждый кадр:

FrameCount++;
currentTime = timeGetTime ();
static unsigned long prevTime = currentTime;
TimeDelta = (currentTime - prevTime) / 1000;
if (TimeDelta > 1.0f)
{
 fps = FrameCount / TimeDelta;
 prevTime = currentTime;
 FrameCount = 0;
    TimeDelta = 0;
}

Вот объявления переменных:

int FrameCount;
double fps, currentTime, prevTime, TimeDelta, TimeElapsed;

Пожалуйста, дайте мне знать, что здесь не так и как это исправить, или, если у вас есть лучший способ подсчета fps. Спасибо !!!!!!

Я использую DirectX 9, кстати, но я сомневаюсь, что это актуально, и я использую PeekMessage. Должен ли я вместо этого использовать оператор if else? Вот мой цикл обработки сообщений:

MSG msg;
ZeroMemory (&msg, sizeof (MSG));

while (msg.message != WM_QUIT)
{
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    Update ();
    RenderFrame ();
}

Ответы [ 5 ]

2 голосов
/ 16 февраля 2010

timeGetTime () неточно. Вместо этого используйте высокопроизводительный счетчик .

Пример кода в другом ответе.

1 голос
/ 14 февраля 2010

Это признак того, что ваш цикл обработки сообщений блокируется вместо просмотра или опроса, так как число кадров в секунду увеличивается, когда вы получаете больше сообщений от мыши. Вам следует рассмотреть возможность использования PeekMessage вместо GetMessage.

РЕДАКТИРОВАТЬ: Кроме того, если вам захочется загрузить процессор, вы также можете добавить PM_NOYIELD, чтобы система не позволяла другим потокам выполняться во время PeekMessage. Из документации PeekMessage :

Вы можете при желании объединить значение PM_NOYIELD с PM_NOREMOVE или PM_REMOVE. Этот флаг предотвращает Система от выпустить любой поток, который ждет звонящего, чтобы бездействовать (см. WaitForInputIdle).

0 голосов
/ 23 мая 2010

О цикле сообщений - я советую заглянуть за сообщения, пока вы его не получите, и затем рендеринг кадра.

Псевдо:

bool renderFrame = true; if (PeekMessage (...)) { // Справиться. renderFrame = false; }

если (renderFrame) рендерит ваш кадр

в противном случае выйдите из функции цикла сообщений (и введите ее снова, или решите через некоторое время, немного зависит от того, как вы структурировали остальную часть основного цикла

0 голосов
/ 16 февраля 2010

Что касается цикла обработки сообщений, да, вы должны использовать оператор if-else, например, так.

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
    TranslateMessage (&msg);
    DispatchMessage (&msg);
} 
else
{
    Update ();
    RenderFrame ();
}

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

Относительно ваших показаний FPS это не так много, на это может повлиять любое количество вещей. Код счетчика fps выглядит так, как будто он выполняет свое предназначение (но с некоторой потерей точности) ..

Мышь управляет камерой? Если да, уверены ли вы, что ввод мыши увеличивает частоту кадров, а не направление?

Вы абсолютно уверены, что ваш код fps запускается только один раз за кадр?

Вы обрабатываете ввод где-нибудь? Если так, что произойдет, если вы отключите этот код и быстро двигаете мышь? Все тот же?

0 голосов
/ 14 февраля 2010

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

currentTime = timeGetTime();
fps = 1000.0f / (currentTime - prevTime);
prevTime = currentTime;

Несмотря на то, что timeGetTime начнет немного неточно на этом этапе, так как числа, вероятно, будут маленькими. QueryPerformanceCounter может быть лучшим таймером для использования.

...