TOP

ABOUT

PROGRAM

DIALY







フレームバッファオブジェクトを使ってみる!

 1.はじめに…
 フレームバッファオブジェクトを使うと,オフスクリーンレンダリングができるとのうわさを手に入れて,プログラムは手元にあるのですが,内部レンダーバッファがどうとか,フレームバッファがどうとかという詳しい話がわからんので,プログラムで使うときのやり方だけまとめておきます。


 2.フレームバッファオブジェクトの使い方
 framebuffer object(FBO)は,OpenGLでプラットフォームに依存せずにオフスクリーンレンダリングを実現する機構だそうです。ちなみにFBOはOpenGL拡張EXT_framebuffer_objectとして規定されているようです。ちなみにOpenGL 2.0の正式仕様にはないようです。このFBOはOpenGL 1.5以上じゃないと使えなかった気がするので,その辺は気を付けてください。
 使い方の流れですが,以下のような感じです。

 <準備>
@ レンダーバッファを作成
A レンダーバッファの設定をする
B 貼り付けるためのテクスチャを作成
C テクスチャの設定をする
D フレームバッファを作成
E フレームバッファの設定をする

 <描画>
@ フレームバッファをバインド (作成したフレームバッファのIDをバインドする)
A ビューポートや視点の設定をなどをして,描画したいものを描く
B フレームバッファのバインド (0をバインドして元に戻す)

 床井研究室のページなんかにもFBOの使い方の説明がありますが,GLEWを使った方が初期化とかの手間が省けるのでGLEWを使っていきます。
あとあと使えるようにFramebufferObject.hとFramebufferObject.cppにクラスを使って記述してみました。
#ifndef _FRAMEBUFFER_OBJECT_H_INCLUDED_
#define _FRAMEBUFFER_OBJECT_H_INCLUDED_

//
// include
//
#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>
using namespace std;

//
// link
//
#pragma comment(lib, "glew32.lib")


//////////////////////////////////////////////////////////////////////////
//  FramebufferObject
//////////////////////////////////////////////////////////////////////////
class FramebufferObject
{
protected:
    int rbWidth;
    int rbHeight;
    GLuint fbID;
    GLuint rbID;
    GLuint texID;

public:
    FramebufferObject();
    ~FramebufferObject();

    void Initialize(int width, int height);
    void Render(void (*render_func)(void));
    void Shutdown();

    int GetWidth() { return rbWidth; }
    int GetHeight() { return rbHeight; }
    GLuint GetFramebufferID() { return fbID; }
    GLuint GetRenderbufferID() { return rbID; }
    GLuint GetTextureID() { return texID; }
};

#endif  // _FRAMEBUFFER_OBJECT_H_INCLUDED_
ヘッダーファイルは上のような感じです。フレームバッファとレンダーバッファ,テクスチャのIDを格納するためにGLuint型の変数を用意しておきます。あとはオフスクリーンでレンダリングするときに必要な幅と高さを格納する変数も用意します。

//
// include
//
#include "FramebufferObject.h"


//////////////////////////////////////////////////////////////////////////
//  FrambufferObject class
//////////////////////////////////////////////////////////////////////////

//----------------------------------------------------------------------------------------------------
//  FramebufferObject
//  Desc : コンストラクタ
//----------------------------------------------------------------------------------------------------
FramebufferObject::FramebufferObject()
{
    rbWidth=0;
    rbHeight=0;
    fbID = 0;
    rbID = 0;
    texID = 0;
}

//----------------------------------------------------------------------------------------------------
//  ~FramebufferObject
//  Desc : デストラクタ
//----------------------------------------------------------------------------------------------------
FramebufferObject::~FramebufferObject()
{
}

//-----------------------------------------------------------------------------------------------------
//  Initialize
//  Desc : 初期化
//-----------------------------------------------------------------------------------------------------
void FramebufferObject::Initialize(int width, int height)
{
    rbWidth = width;
    rbHeight = height;

    // GLEWの初期化
    if ( glewInit() != GLEW_OK )
    {
        cout << "Error : GLEWの初期化に失敗しました\n";
        exit(0);
    }

    // サポートチェック
    if (! GLEW_EXT_framebuffer_object ) 
    {
        cout << "Error : フレームバッファオブジェクトがサポートされていません\n";
        exit(0);
    }
        
    // テクスチャの設定
    glGenTextures(1, &texID);
    glBindTexture(GL_TEXTURE_2D, texID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rbWidth, rbHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

    // レンダーバッファの設定
    glGenRenderbuffersEXT(1, &rbID);
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbID);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
        GL_DEPTH_COMPONENT24, rbWidth, rbHeight);

    // フレームバッファの設定
    glGenFramebuffersEXT(1, &fbID);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbID);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
        GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texID, 0);
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
        GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbID);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

//-----------------------------------------------------------------------------------------------------
//  Render
//  Desc : テクスチャへ描画
//-----------------------------------------------------------------------------------------------------
void FramebufferObject::Render(void (*render_func)(void))
{
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbID);
    render_func();
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

//-----------------------------------------------------------------------------------------------------
//  Shutdown
//  Desc : 後片付け
//-----------------------------------------------------------------------------------------------------
void FramebufferObject::Shutdown()
{
    glDeleteFramebuffersEXT(1, &fbID);
    glDeleteRenderbuffersEXT(1, &rbID);
    glDeleteTextures(1, &texID);

    fbID = 0;
    rbID = 0;
    texID = 0;
}
こんな感じになっています。


 3.おわりに…
 FBOの詳しい説明はおそらく,More OpenGL GameProgramingとかOpenGL Super Bibleとか赤本あたりに載っていると思います。
 説明がだめだめで,すいませんです。


 Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2005 Professionalを用いています。