OpenGLプログラミング/Supersampling
はじめに
[編集]白い背景の上に黒い線を描画するときに、コンピュータやGPUは、最も基本的なレベルにおいて、どのピクセルを黒にするべきかを決定します。 これは、水平または垂直のラインなら非常にうまくいきます。 しかし、ラインが斜めである場合は、ラインがスムーズにならず、ギザギザになることがすぐにわかります。 しかし、黒と白だけを使用するのではなく、グレーのピクセルを戦略的に配置すれば、目を欺いてラインがよりスムーズに見えるようにできます。 これは、アンチエイリアシングと呼ばれています。 アンチエイリアスする方法には様々なものがあり、ライン、他の形状、あるいはテキストへのものもあります。 この本の中で最古のトリックは、倍の大きさでラインを描き、その後結果の白黒画像を元のサイズに縮小して、2×2ピクセルの各グループの平均を取ることです。 結果として得られる画像は、グレーの5段階の明暗になり(黒と白を含む)、大きく改善されるはずです。 もちろん、3倍、4倍またはそれ以上の太さの線を引くこともできます(10、17またはそれ以上の明暗のグレーにも)。 このテクニックは、スーパーサンプリングと呼ばれています。 かなり大きな画像をレンダリングする必要があるため、非常に時間を食い、限られた量の明暗しか与えません。 しかし、大きな利点は、この手法が非常にシンプルで、ライン、テキスト、または3Dシーンを問わず、 *あらゆる*種類の画像で動作するということです。
Supersampling using the accumulation buffer
[編集]アキュムレーションバッファを使用して同じテクニックを実装することもできます。 しかし問題は、アキュムレーションバッファが通常のカラーバッファより大きくなく、ぴったり同じ大きさしかないということです。 その代わりに、同じシーンを複数回レンダリングして、そのたびごとにほんの少しづつシフトさせることができます。 次のコードを使用して model-view-projection 行列を設定するところから始め、その後フレームをレンダリングするとします:
glm::mat4 modelview = glm::lookAt(...);
glm::mat4 projection = glm::perspective(...);
glm::mat4 mvp = projection * modelview;
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
draw_scene();
glSwapBuffers();
2x2のアンチエイリアスを行いたい場合、シーンを(0, 0)、(0.5, 0)、(0, 0.5)、(0.5, 0.5)ピクセルそれぞれシフトさせます。 これは簡単にできます。頂点に model-view-projection 行列を適用した後、私たちはスクリーン座標をもち、(0, 0)が左下、そして(1, 1)が右上のビューポートに対応します。 なので(0.5, 0.5)ピクセルだけシフトさせるために、(0.5 / W, 0.5 / h)単位の変換を適用する必要があり、ここでwとhはビューポートのピクセル単位での幅と高さです。 これが結果です:
glm::mat4 modelview = glm::lookAt(...);
glm::mat4 projection = glm::perspective(...);
for(int i = 0; i < 4; i++) {
glm::vec3 shift = glm::vec3((i % 2) * 0.5 / w, (i / 2) * 0.5 / h, 0);
glm::mat4 aa = glm::translate(glm::mat4(1.0f), shift);
glm::mat4 mvp = aa * projection * modelview;
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
draw_scene();
glAccum(i ? GL_ACCUM : GL_LOAD, 0.25);
}
glAccum(GL_RETURN, 1);
glSwapBuffers();
エクササイズ
[編集]- この手法を、前のチュートリアルのいずれかに適用してみましょう。
- 3x3、4x4、8x8、16x16ピクセルのアンチエイリアシングを試してみましょう。 品質に何も得るものがないのはどのポイントの後だと思いますか?
- これは大きな画像をレンダリングして、それをスケールダウンさせることと本当に同じでしょうか? 1ピクセルより細いラインではどうでしょうか?
- この手法をモーションブラーと効果的に組み合わせることはできるでしょうか?