Тема вроде широко известная, но есть впечатление, что самоочевидным и общеизвестным является далеко не всё.
Поэтому видится смысл поговорить вслух.
Подобные темы были, ну вот будет тема обновлённая.
Чтиво:
http://gafferongames.com/game-physics/fix-your-timestep/
http://www.koonsolo.com/news/dewitters-gameloop/
http://gameprogrammingpatterns.com/game-loop.html
http://www.gamedev.ru/community/gamedev_lecture/articles/game_orhetecture
https://www.wired.com/2013/02/john-carmacks-latency-mitigation-strategies/
В качестве затравки набросок:
// There is some argument about double vs. fixed-point: // https://twitter.com/ID_AA_Carmack/status/418158611664097280 // https://tomforsyth1000.github.io/blog.wiki.html ( A matter of precision ) double update_dt=1.0/50.0; // Game logic updates 50 times per second. double max_fps=250.0; // FPS limiter. double max_lag=0.125; double t0,t1=get_time(); double t_render=t1; double delta=0.0; // Time to next update. while( !quit) { t0=t1; t1=get_time( ); delta-=( t1-t0); if( delta>2.0*update_dt) { // Something weird happened. // Maybe time got reset. delta=0.0; // Whatever. t_render=t1; } if( delta<-max_lag) { // We are lagging behind. // Prevent unbound delta accumulation (maybe update() takes more than update_dt). delta=-max_lag; } while( delta<=0.0) { update( world); delta+=update_dt; } if( ( t1-t_render)*max_fps>=1.0) { t_render=t1; double time_since_update=( get_time( )-t1)+( update_dt-delta); render( world,time_since_update); // For extrapolation. if( vsync) wait_for_vsync( ); swap_buffers( ); } else { // Do not render too often: see http://www.teamliquid.net/forum/starcraft-2/139794-blizzard-confirms-sc2-overheating-bug . sleep( 0.001); } }
Можно критиковать.
Вопросы:
1. Мысль из http://www.gamedev.ru/community/gamedev_lecture/articles/game_orhetecture о эффективности порядка Render(); Update(); Present(); - ещё актуальна?
2. VSync здесь вообще внятно сделан?
Если игровой цикл правильно организован, то всё шелестит очень быстро.
Ну сделал так чувак wait_for_vsync(); Мы же не видим что там внутри делается.
Что беспокоит-то ?
У Rastertek всё неплохо разобрано про это дело - игровой цикл.
Лучше по порядку про плюсы и минусы, а не сумбурно кучей.
Что не так с : Render(); Update(); Present(); ?
О каких конкретно "ошибках" речь ?
bykabak
> О каких конкретно "ошибках" речь ?
видимо о распространенной херне, когда кто-то делает update где попало, а потом у него объекты начинают о камеры отставать.
> Что не так с : Render(); Update(); Present(); ?
Ну мы вроде как прошлый кадр рендерим таким способом.
Т. е. поинт, видимо - ценой latency улучшить throughput т. к. зависимость односторонняя (update->render).
Ну и вопрос - акутально ли? Дейстительно улучшает?
FordPerfect
Т. е. поинт, видимо - ценой latency улучшить throughput т. к. зависимость односторонняя (update->render).
Я не знаю, вас в школе не учили выражать свои мысли ? ( Я ничего не понял )
Если честно, код в старте топика какой-то необычный. :) Зачем вы его притянули сюда ? Чем он вас зацепил ?
Вот у Rastertek так vsync сделан : http://www.rastertek.com/dx11tut03.html
Развёрнутее:
в порядке Render(); Update(); Present(); (по сравнению с интуитивным Update(); Render(); Present();) latency выше:
// ..... Render(); Update(); // Нажали клавишу. Present(); // ... Render(); // ... Update(); // ... Present(); // Увидели реакцию на нажатие. Render(); Update(); Present(); // .....
против
// ..... Update(); // Нажали клавишу. Render(); // ... Present(); // Увидели реакцию на нажатие. Render(); Update(); Present(); Render(); Update(); Present(); // .....
Но throughput может быть лучше, т. к. update() в идеале не зависит от render() и не обязан дожидаться того, что render() ну например данный на GPU зальёт. Т. е. они могут работать более внахлёст. В обратной ситуации это более проблематично, т. к. render() зависит от update() - пока не обновились - непонятно, что рисовать.
Код в старте - мой. Как пример "как бы я сейчас делал"; ну и для затравки разговора.
Я полагаю, что всё должно идти по порядку, и, возможно, что-то не каждый кадр выполняется. Что именно - решает разработчик, исходя из его видения как должно работать.
Вы видите решение с vsync так, как вы решили. Ссылку на альтернативный вариант я вам дал.
Из вашей темы непонятно, что конкретно вас беспокоит ?
По винду цикл должен быть таким:
while (true) { while ( UpdateStep( )) {}; if ( PeekMessage( &msg, hwnd, 0, 0, PM_REMOVE)) { if ( msg.message == WM_QUIT) break; TranslateMessage( &msg); DispatchMessage( &msg); } }
Апдейт степ, в котором физика/логика должен быть каким-то таким:
bool UpdateStep() { bool Out = World->Time( ) + World->TimeStep( ) <= get_time( ); if ( Out) World->DoUpdateStep( ); return Out; }
А рендер мира должен быть в оконной функции в обработчике WM_PAINT
MrShoor
если update будет занимать больше времени чем World->TimeStep, то приложение перестанет реагировать на события?
kipar
> если update будет занимать больше времени чем World->TimeStep, то приложение
> перестанет реагировать на события?
А смысл реагировать? Ну ок, можно переделать, но оно как было не играбельно, так и останется.
void Update() { long long NewTime = get_time( ); int UpdateCount = ( NewTime - World->Time( )) / World->TimeStep( ); for ( int i = 0; i < UpdateCount; i++) World->DoUpdateStep( ); return; }
А оконый цикл такой:
while (true) { Update( ); if ( PeekMessage( &msg, hwnd, 0, 0, PM_REMOVE)) { if ( msg.message == WM_QUIT) break; TranslateMessage( &msg); DispatchMessage( &msg); } }
MrShoor
ну хотя бы чтоб выйти можно было. Да и вообще, по-моему лучше если игра тормозить начинает чем если она совсем виснет. Против исправленной версии ничего не имею.
—-
а, в исправленном еще остаток дельты с прошлого шага не учитывается. Но в общем суть ясна. учитывается
А не лучше ли вынести в 2 разных потока Update и Render?
FordPerfect
> Игровой цикл
Пытаюсь от него уйти. Запустить по крайней мере три процесса отдельно: графика, физика и логика.
dave
И потом все это синхронизировать.
Тема в архиве.