2015-08-23 1 views
0

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

 //g_dwLastfps & currenttime are equal to timeGetTime() 
     float fFrameLimit = 0; 
     if (g_nFrameLimitValue > 0) //g_nFrameLimitValue = user defined 
      fFrameLimit = 1000/g_nFrameLimitValue; 
     while ((currentTime - g_dwLastTime) < fFrameLimit) 
     { 
      // -1 = wait an extra ms. seemed to help accuracy some 
      Sleep((float)fFrameLimit - ((currentTime - g_dwLastTime)) - 1); 
      currentTime = timeGetTime(); 
     } 
     g_dwLastTime = currentTime; 

ответ

0

Я могу думать о довольно простое решение:

uint64_t last_time = 0; 
uint64_t current_time = time(); 
uint64_t frame_limit_ms = 17; // 60fps = 16.666... ms/f 
uint64_t frame_diff = frame_limit_ms; 

sleep(frame_limit_ms); 

while(running){ 
    last_time = current_time; 
    current_time = time(); // get frame start time in milliseconds 
    frame_diff = current_time - last_time; // get time since last frame in ms 

    if(frame_diff < frame_ms_limit){ 
     sleep(frame_ms_limit - frame_diff); 

     // need to do a re-calculation for accuracy 
     current_time = time(); 
     frame_diff = current_time - last_time; 
    } 

    do_physics(frame_diff); 
    draw_scene(); 
    swap_buffers(); 
} 

Что выглядит как то, что у вас есть, но не использует float так должно быть быстрее и с точностью до одной единицы время (миллисекунды в этом случае).

Если вы хотите, чтобы он был более точным, используйте более точный блок (наносекунды) и преобразуйте его обратно в миллисекунды, если вам нужно.

+0

Но, не используя результат сна в том же номере, что я частотой кадров я бегу в настоящее время (пользователь может выбрать anythign до 1000fps, из-за ВЗ, как анимации реагируют на FrameRate изменения. Некоторые игроки предпочитают супер высокие темпы движения кадров b/c выглядят более гладкими, в то время как другие предпочитают нормальную частоту кадров)? – Jeff

+0

Подождите, что здесь конкретно? Конечно, 1000 кадров в секунду будет выглядеть более плавным, чем 30 кадров в секунду. – CoffeeandCode

+0

И «спать» не будет узким местом ... если явно не указано – CoffeeandCode

0

Одна проблема с примером кода заключается в том, что last_time обновляется до current_time, которое обновляется до времени(), что может привести к дрейфу с течением времени. Чтобы этого избежать, last_time должен основываться на исходном показании времени() и расширен на требуемую задержку для каждого кадра. Следующий код на основе окон похож на то, что используется в играх, чтобы поддерживать поток с фиксированной частотой без дрейфа. uRem используется для обработки частот, которые не являются точными кратными тактовой частоте. dwLateStep - это вспомогательное средство отладки, которое получает каждый экземпляр, где время шага превышено. Код совместим с Windows XP, где Sleep (1) может занимать до 2 мс, поэтому он проверяет задержку> = 2 мс перед использованием Sleep (1).

/* code for a thread to run at fixed frequency */ 
typedef unsigned long long UI64;  /* unsigned 64 bit int */ 
#define FREQ 400      /* frequency */ 
DWORD dwLateStep;     /* late step count */ 
LARGE_INTEGER liPerfFreq;    /* 64 bit frequency */ 
LARGE_INTEGER liPerfTemp;    /* used for query */ 
UI64 uFreq = FREQ;      /* process frequency */ 
UI64 uOrig;        /* original tick */ 
UI64 uWait;        /* tick rate/freq */ 
UI64 uRem = 0;       /* tick rate % freq */ 
UI64 uPrev;        /* previous tick based on original tick */ 
UI64 uDelta;       /* current tick - previous */ 
UI64 u2ms;        /* 2ms of ticks */ 
UI64 i; 

    /* ... */ /* wait for some event to start thread */ 
    QueryPerformanceFrequency(&liPerfFreq); 
    u2ms = ((UI64)(liPerfFreq.QuadPart)+499)/((UI64)500); 

    timeBeginPeriod(1);     /* set period to 1ms */ 
    Sleep(128);       /* wait for it to stabilize */ 

    QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp); 
    uOrig = uPrev = liPerfTemp.QuadPart; 

    for(i = 0; i < (uFreq*30); i++){ 
     /* update uWait and uRem based on uRem */ 
     uWait = ((UI64)(liPerfFreq.QuadPart) + uRem)/uFreq; 
     uRem = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq; 
     /* wait for uWait ticks */ 
     while(1){ 
      QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp); 
      uDelta = (UI64)(liPerfTemp.QuadPart - uPrev); 
      if(uDelta >= uWait) 
       break; 
      if((uWait - uDelta) > u2ms) 
       Sleep(1); 
     } 
     if(uDelta >= (uWait*2)) 
      dwLateStep += 1; 
     uPrev += uWait; 
     /* fixed frequency code goes here */ 
     /* along with some type of break when done */ 
    } 

    timeEndPeriod(1);     /* restore period */ 

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

  • Нет связанных вопросов^_^