OpenGLプログラミング/Motion Blur
はじめに
[編集]カラーバッファ、デプスバッファ、ステンシルバッファとは別に、ほとんどのグラフィックスカードには、アキュムレーションバッファといわれるオフスクリーンのフレームバッファが用意されています。 これらは基本的に、1色につき16ビット以上の精度を持つカラーバッファです。 しかし、アキュムレーションバッファに直接描画することはできません。 その代わりに、アキュムレーションバッファ全体を一度に処理する演算がいくつかあります。
glAccum(GL_LOAD, value)
- ノーマルカラーバッファの内容をコピーして、
value
で乗算し、アキュムレーションバッファへ。 glAccum(GL_RETURN, value)
- アキュムレーションバッファの内容をコピーし、
value
で乗算し、カラーバッファへ。 glAccum(GL_ACCUM, value)
- ノーマルカラーバッファの内容を加算し、
value
で乗算し、アキュムレーションバッファへ。 glAccum(GL_ADD, value)
- アキュムレーションバッファ内のすべてのピクセルに
value
を加算する。
l glAccum(GL_MULT, value)
: アキュムレーションバッファ内のすべてのピクセルに value
を乗算する。
すべての場合において、 value
は浮動小数点数(GLfloat)です。
これらの関数を使うと、複数のフレームの(重み付けされた)和や平均を簡単に計算することができます。
このチュートリアルでは、この関数を使って、ほとんどのOpenGLプログラムにモーションブラーを簡単に追加する方法を紹介します。
モーションブラー
[編集]モーションブラーは、オブジェクトが(カメラに対して)非常に速く動いたり、カメラの露光時間が非常に長くなったりして、露光中に一部の物体が半ピクセル以上動いてしまい、それが不鮮明に見えることで発生します。 モーションブラーは通常、好ましいものではありませんが、実際のカメラでは避けるのが難しい場合があります。 なぜなら、露光時間はシーン内の光の量に大きく依存するからです。 光量が少なければ露光時間が長くなり、ブレの影響が強くなります。 屋外でビデオカメラを使って撮影した映像と、室内で同じカメラを使って撮影した映像の「感じ」が違うのは、このためです。
モーションブラーの再現
[編集]アキュムレーションバッファを使ったモーションブラー効果は、実はとても簡単に作ることができます。
- 通常のOpenGLアプリケーションの動作はこのようになっています
for (;;) { do_time_evolution(timestep); draw_scene(); glSwapBuffers(); wait_until_next(timestep); }
ここで、関数 do_time_evolution()
は、シーン内の移動するオブジェクトの座標や、カメラ自体の動きの更新を行います。
シーンが描画された後、glSwapBuffers()
によって画面に表示されますが、オプションとしてフレームレートを制限するためにしばらく待ちます。
- モーションブラーを追加するには、より小さなタイムステップでシーンを複数回描画し、その平均値のみを表示することができます
int n = <number of frames to accumulate> int i = 0; for (;;) { do_time_evolution(timestep / n); draw_scene(); if (i == 0) glAccum(GL_LOAD, 1.0 / n); else glAccum(GL_ACCUM, 1.0 / n); i++; if (i >= n) { i = 0; glAccum(GL_RETURN, 1.0); glSwapBuffers(); wait_until_next(timestep); } }
多くのフレームを蓄積することで最高の効果が得られますが、GPUの能力によってすぐに制限されてしまいます。
蓄積するフレーム数を設定できるようにするか、1回のtimestep
でレンダリングできるフレーム数を自動的に決定するようにするのがよいでしょう。
練習問題
[編集]- これまでのチュートリアルのどれかにモーションブラーを追加してみましょう。より面白いのは、mini-portalとglescraftで、シーンの中を歩き回れるようになっています。
- シーンに後処理効果を加える場合、モーションブラーを適用する前と後のどちらにすべきでしょうか?
- GPUがアキュムレーションバッファを提供しない場合、テクスチャにレンダリングすることで
glAccum()
の機能を再現できますか?