j3259の日記: OpenGL
- GLUTによる「手抜き」OpenGL入門
- The OpenGL Utility Toolkit (GLUT) Programming Interface API Version 3
- NeHe Productions
- Nate Robins tutors
リアルタイムの精度はいらないけど、物理のシミュレーションをしたいので、ftp(モデルの更新)を固定したい。
glutIdleFunc(idle) で idle を登録すると、する事がなくなるたびに idleが呼び出される。 簡単なサンプルコードではこの idle でモデルの更新とフレームの強制更新を書いてるのが多い。 つまり、レンダーしてない時はモデルの更新をしてるっていう忙しいコードになる。これをやると、モデルの更新の頻度がマシン依存して、速いマシンで走らせると速く動く。ダサい。
更新頻度を固定するには更新の間隔を固定すればいい。予定時刻よりも早くアイドル状態になったら予定時刻まで待てばいい。ここでビジーループで待つとCPU 100%状態になってダサい。プロセスを眠らせる標準的なコードが見つからなかったので Windows の Sleep 関数を使う。
void idle(void)
{
static clock_t lastTick = 0;
clock_t now = clock();
int miliSec = ((now - lastTick) * 1000) / CLOCKS_PER_SEC;
if (miliSec < 16) {
#ifdef WIN
Sleep(16 - miliSec);
#endif
#ifdef BSD
sleep((16 - miliSec) / 1000.0);
#endif
return;
} //
lastTick = now;
glutPostRedisplay();
}
とここまで書いて、GLUT にタイマーがあることを思い出す。
glutTimerFunc(16, timer, 1) で timer関数を登録。
void timer(int a_id) {
clock_t start = clock();
updateModel();
glutPostRedisplay();
clock_t end = clock();
int miliSec = ((end - start) * 1000) / CLOCKS_PER_SEC;
if (miliSec < 16) {
glutTimerFunc(16 - miliSec, timer, 1);
} else {
glutTimerFunc(0, timer, 1);
} // if
}
なんで 16msec なのかというと、僕が使ってる液晶ディスプレイのリフレッシュレートが 60Hz だから。つまり、毎秒60フレーム以上描画してもディスプレイに反映されなきゃ仕方がない。1000 / 60 が 16.666。clockの精度がミリ秒なんで、整数演算だけで済むように 16ミリ秒ごとに画面を描画して、0.666ミリ秒後にディスプレイに反映されるはず。というロジックなんだけど、本当はビデオカードとかドライバで直接色々書き込まれてて 60Hz 以上の頻度でリフレッシュできるのかもしれません。だけど、60 fps以上で更新してもヒトの目には分からんでしょう。それよりも、できるだけ AIに時間を割きたいので分からない範囲で fpsはできるだけ落として更新間隔を長く取ったほうがいい。更新間隔が長いほど計算と描画に時間が割けるわけで。
オブジェクトの数が多くなって、さらにテクスチャとかライティングとかが入ってくると、16msec の間で何ができるかっていうのは CPU と GPU の速さに依存してくると思う。最大限のディテールで描画してみて、16msec 内に収まらなければちょっとずついらない物から省いていくとか、AIの思索のレベルを落とすとかいう処理が必要になってくる。その点コンソール用のゲームはハードウェア決め打ちができる。
OpenGL More ログイン