Frame Buffer Objectについて

FBOとは

OpenGL - PBOでPBOについて説明しました. PBOはピクセルデータを格納するGPU側のバッファであり,これを利用してフレームバッファからデータを転送していました. フレームバッファは,OpenGLのレンダリングパイプラインにおいて最終的なレンダリング結果を描画するのに用いられ, システムにもよりますが一般的に,複数のカラーバッファ,デプスバッファ,ステンシルバッファ,アキュムレーションバッファの 集合になっています. このフレームバッファをオフラインで用いることができるのがFrame buffer object(FBO)です. フレームバッファと同じように,FBOもカラー,デプス,ステンシルバッファを持ちます(アキュムレーションバッファはサポートされていないようです). また,FBOではrenderbuffer object(RBO)とテクスチャオブジェクトを関連付けることで, テクスチャへのレンダリングが可能となります.

FBOの使い方

FBOのIDや関連付けたRBO,テクスチャをまとめて管理するために以下のような構造体を作成します.

// FBO構造体
struct RxFBO
{
	GLuint id;		// FBOのID
	int w, h, c;	// バッファの幅,高さ,チャンネル数
	int size;		// バッファのサイズ(sizeof(GLubyte)*w*h*c)
	GLuint tex;		// 関連付けたテクスチャの名前
	GLuint rboid;	// 関連付けたRBOのID
};

FBOの作成手順

  1. glGenFramebufferでFBO生成
    void glGenFramebuffers(GLsizei n, GLuint* framebuffers);
  2. glBindFramebufferでバインド
    void glBindFramebuffer(GLenum target, GLuint framebuffer);
/*!
 * FBOの作成
 * @param[out] fbo FBO
 */
void CreateFBO(RxFBO &fbo)
{
	// RBO作成
	glGenRenderbuffers(1, &fbo.rboid);
	glBindRenderbuffer(GL_RENDERBUFFER, fbo.rboid);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fbo.w, fbo.h);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);

	// FBO作成
	glGenFramebuffers(1, &fbo.id);
	glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);

	// テクスチャ,RBOと対応付け
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.tex, 0);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo.rboid);

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

FBOの破棄

glDeleteFramebuffersを用いる.

void glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
/*!
 * FBO削除
 * @param[inout] fbo FBO
 */
void DeleteFBO(RxFBO &fbo)
{
	glDeleteFramebuffers(1, &fbo.id);
	glDeleteRenderbuffersEXT(1, &fbo.rboid);
	fboid = 0;
	rboid = 0;
}

FBOの使用例

PBOの時のように,FBOを介してテクスチャをターゲットにして描画して, それを貼り付けたポリゴンを描画します.

RxFBO g_fboScreen;

void RenderSceneWithFBO(RxFBO &fbo)
{
	if(!fbo.id) return;

	glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);

	glViewport(0, 0, fbo.w, fbo.h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(RX_FOV, (float)(fbo.w/fbo.h), 0.2f, 1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	RenderScene();

	glFlush();

	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	glBindTexture(GL_TEXTURE_2D, fbo.tex);
	glGenerateMipmap(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, 0);
}

void RenderImage(RxFBO &fbo)
{
	glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glViewport(0, 0, g_iWinW, g_iWinH);

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	//glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
	Projection();

	glMatrixMode( GL_MODELVIEW);
	glLoadIdentity();

	glDisable(GL_LIGHTING);
	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

	glBindTexture(GL_TEXTURE_2D, fbo.tex);

	glPushMatrix();

	g_tbView.TrackballApply();	// マウスによる回転・平行移動の適用

	glColor4d(0.0, 0.0, 1.0, 1.0);
	glBegin(GL_QUADS);
	glTexCoord2d(0.0, 1.0);	glVertex3d(-0.8,  0.8, 0.0);
	glTexCoord2d(1.0, 1.0);	glVertex3d( 0.8,  0.8, 0.0);
	glTexCoord2d(1.0, 0.0);	glVertex3d( 0.8, -0.8, 0.0);
	glTexCoord2d(0.0, 0.0);	glVertex3d(-0.8, -0.8, 0.0);
	glEnd();
	glPopMatrix();

	glBindTexture(GL_TEXTURE_2D, 0);

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glDisable(GL_TEXTURE_2D);

	glutSwapBuffers();
}

void Display(void)
{
	RenderSceneWithFBO(g_fboScreen);
	RenderImage(g_fboScreen);
}

シーンの例としては以下,

/*!
 * シーン描画
 */
void RenderScene(void)
{
	static double ang = 0.0;

	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glDisable(GL_CULL_FACE);
	glEnable(GL_LIGHTING);

	glPushMatrix();

	glTranslatef(0.0, 0.0, -4.0);
	glRotatef(ang, 0.0, 1.0, 0.3);

	// 図形の描画
	glPushMatrix();
	glColor3d(0.0, 0.0, 1.0);
	glutSolidTeapot(1.0);
	glPopMatrix();

	glPopMatrix();

	ang = (ang >= 360.0) ? 0.0 : ang+1;
}

上記シーンで描画した結果を以下に示します.

teapot_fbo_1.jpg

添付ファイル: fileteapot_fbo_1.jpg 2575件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2024-03-08 (金) 18:06:05