以前にDirectX11でMSAAというタイトルでテクスチャに対するMSAAをやってみましたが今回はそれのOpenGL版をやってみたいと思います。結果はこんな感じです。画像を切った貼ったしたので、ねつ造と言われてしまうかも・・・。
必要になるGL拡張
最近のOpenGL対応ボードならば問題ないと思いますが、OpenGL 2.1対応とか言われているボードでは下記の拡張が存在するか確認が必要です。
- GL_EXT_framebuffer_blit
- GL_EXT_framebuffer_multisample
これが NVの拡張であってもとりあえず使えるには使えると思います。
手順
まず、FBOが2つ必要になります。内訳としては次のような感じです。
- MSAA描画するFramebufferObject(fbo)を作成する.
- MSAA処理されたテクスチャを得るためのfboを作成する
描画時の流れはこんな感じです。
- MSAAのFBOをバインドして描画を行う
- MSAAのFBOから通常FBOへBlitFramebuffer
- 通常FBOの中にアタッチされているテクスチャを使用
このBlitFramebufferという処理がDirectXでいうところの Resolve関数になるかなと思います。
この処理によって通常のテクスチャとしてMSAAがかかった描画結果を使用することができます。
DirectX時はテクスチャに対して Resolve 出来ましたが GLではそれが直テクスチャ指定できないので一度FBOを作る必要があるようです。
プログラムコード
まずMSAAのFBOを作るところです。
MSAAの場合はテクスチャをアタッチするのではなくレンダーバッファをMSAA用のものを作成し、それを使用するようにします。
GLuint rb[2] = { 0 };
glGenFramebuffers( 1, &fboMSAA );
glGenRenderbuffers( 2, rb );
glBindRenderbuffer( GL_RENDERBUFFER, rb[0] );
glRenderbufferStorageMultisample( GL_RENDERBUFFER, 4, GL_RGBA, 256, 256 );
glBindRenderbuffer( GL_RENDERBUFFER, rb[1] );
glRenderbufferStorageMultisample( GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, 256, 256 );
glBindFramebuffer( GL_FRAMEBUFFER, fboMSAA );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb[0] );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb[1] );
Resolve先のFBOを作成します。
GLuint depthRB;
glGenRenderbuffers( 1, &depthRB );
glBindRenderbuffer( GL_RENDERBUFFER, depthRB );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 256 );
glGenFramebuffers( 1, &fbo );
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0 );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRB );
描画の時の Resolve関連はこんな感じになります。
glBindTexture( GL_TEXTURE_2D, 0 ); // 描画先テクスチャのバインドを解除しておく.
glBindFramebuffer( GL_FRAMEBUFFER, fboMSAA );
/* レンダーターゲットへ描画処理 */
// いわゆるResolve処理.
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fbo );
glBindFramebuffer( GL_READ_FRAMEBUFFER, fboMSAA );
glBlitFramebuffer( 0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_LINEAR );
/* レンダーテクスチャを使用 */
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glBindTexture( GL_TEXTURE_2D, renderTex );
// 描画処理.
注意点など
glBlitFramebufferのバッファフラグは OR 結合で複数指定は出来ないようなので注意しましょう。
MSAAの動作確認時には、小さいテクスチャに対して描画してそれを拡大して貼るのがおすすめです。また、元々は水平垂直のポリゴンを回転させて斜めになるようにして描画したものを使用するとMSAAのかかり具合の確認がしやすいです。
確認の際にはテクスチャフィルタをポイントサンプルとなるようにしておくことや、ドットバイドットの表示をしておくことも忘れがち&やっちゃいがちなので注意しましょう。
(現にDX11のときにはうまくできたのに、GL版実装中で自分が↑をやっちゃいました)