OpenGL アプリケーションを画面にレンダリングする FPS を正確に設定できる確実な方法を見つけようとしています。1000/fps ミリ秒スリープすることである程度はできますが、レンダリングに必要な時間は考慮されていません。fps を希望の量に制限する最も一貫した方法はどれですか?
7 に答える
opengl で wglSwapIntervalEXT を使用して vblank に同期できます。素敵なコードではありませんが、機能します。
http://www.gamedev.net/topic/360862-wglswapintervalext/#entry3371062
bool WGLExtensionSupported(const char *extension_name) {
PFNWGLGETEXTENSIONSSTRINGEXTPROC _wglGetExtensionsStringEXT = NULL;
_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
if (strstr(_wglGetExtensionsStringEXT(), extension_name) == NULL) {
return false;
}
return true;
}
と
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL;
if (WGLExtensionSupported("WGL_EXT_swap_control"))
{
// Extension is supported, init pointers.
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
// this is another function from WGL_EXT_swap_control extension
wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
}
OpenGL は低レベルのグラフィックス API にすぎないため、このようなものが OpenGL に直接組み込まれていることはありません。
しかし、あなたの論理には少し欠陥があると思います。以下ではなく:
- フレームを描く
- 1000/fps ミリ秒待機
- 繰り返す
これを行う必要があります:
- タイマーを開始
- フレームを描く
- タイマーを停止
- 待機 (1000/fps - (停止 - 開始)) ミリ秒
- 繰り返す
このようにして、本来あるべき量だけを待っている場合、1 秒あたり 60 フレーム (または目標としているもの) に非常に近くなるはずです。
OpenGL 自体には、フレームレートを制限できる機能はありません。限目。
ただし、最新の GPU には、フレームレート、フレーム予測などをカバーする多くの機能があります。John Carmack が、いくつかの機能を利用できるようにするためにプッシュしたイシューがありました。そして、NVidia のアダプティブ シンクがあります。
それはあなたにとって何を意味しますか?それはGPUにお任せください。描画は完全に予測不可能であると想定し (OpenGL のみに固執する場合と同様)、イベントの時間を自分で計り、ロジックの更新 (物理など) を描画とは別に維持します。そうすれば、ユーザーはこれらすべての高度なテクノロジーの恩恵を受けることができ、もう心配する必要はありません。
スリープを使用しないでください。その場合、アプリケーションの残りの部分は、それらが終了するまで待機する必要があります。
代わりに、経過時間を追跡し、1000/fps に達した場合にのみレンダリングします。タイマーが満たされていない場合は、スキップして他のことを行います。
シングル スレッド環境では、絶対に 1000/fps で描画することだけを行う場合を除いて、正確に 1000/fps で描画することを確認するのは困難です。より一般的で堅牢な方法は、すべてのレンダリングを別のスレッドで実行し、そのスレッドをタイマーで起動/実行することです。これははるかに複雑な問題ですが、求めているものに最も近いものになります。
また、レンダリングを発行するのにかかる時間を追跡しておくと、いつレンダリングするかをその場で調整するのに役立ちます。
static unsigned int render_time=0;
now = timegettime();
elapsed_time = last_render_time - now - render_time;
if ( elapsed_time > 1000/fps ){
render(){
start_render = timegettime();
issue rendering commands...
end_render = timegettime();
render_time = end_render - start_render;
}
last_render_time = now;
}
もう 1 つのアイデアは、WaitableTimers を使用することです (Windows などで可能な場合)。
基本的な考え方:
while (true)
{
SetWaitableTimer(myTimer, desired_frame_duration, ...);
PeekMsg(...)
if (quit....) break;
if (msg)
handle message;
else
{
Render();
SwapBuffers();
}
WaitForSingleObject(myTimer);
}
詳細: fps 情報を制限する方法