Pixel Buffer Objectについて

**PBOとは [#w2274e15]
Pixel Buffer Object(PBO)はVBOをピクセルデータを格納できるように拡張したものです.
PBOではDMAを用いてビデオカードとのデータのやり取りを行うので,CPUサイクルに影響されずに
高速に転送できます.また,フレームバッファやテクスチャメモリとのデータのやり取りも
可能です(glReadPixels, glDrawPixels, glGetTexImage, glTexImage2D, glTexSubImage2Dなどを使用).

**PBOの使い方 [#ode464de]
PBOの作成はVBOとほぼ同じです.
ただし,glBindBufferなどに指定するtargetに
-GL_PIXEL_PACK_BUFFER : ピクセルデータをPBOへ転送(glReadPixel, [[glGetTexImage:http://www.opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml]])
-GL_PIXEL_UNPACK_BUFFER : PBOからピクセルデータを取得(glDrawPixels, glTexImage2D, glTexSubImage2D)
を指定します.
例えば,フレームバッファとのデータのやり取りならば,
-OpenGLフレームバッファ -> PBO : GL_PIXEL_PACK_BUFFERを指定して,glReadPixelsを実行
-PBO -> OpenGLフレームバッファ : GL_PIXEL_UNPACK_BUFFERを指定して,glDrawPixelsを実行

また,VBOと同様にglMapBuffer, glUnmapBufferを用いてPBOをアプリケーション側のメモリにマッピングすることができます.

PBO作成,破棄関数例は以下.
#code(C){{
/*!
 * PBOの作成
 * @param[out] pbo 名前
 * @param[in] w,h,c 幅,高さ,チャンネル数
 */
void CreatePBO(GLuint &pbo, int w, int h, int c = 3)
{
	// PBO作成とバインド
	glGenBuffers(1, &pbo);
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);

	glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, w*h*c, 0, GL_DYNAMIC_DRAW);	// バッファの作成と初期化

	glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
}

/*!
 * PBOの削除
 * @param[inout] pbo 名前
 */
void DeletePBO(GLuint &pbo)
{
	glBindBuffer(GL_ARRAY_BUFFER, pbo);
	glDeleteBuffers(1, &pbo);
	pbo = 0;
}
}}


**PBO使用例 [#fbc1fb3c]
PBOの使用例として,フレームバッファに描画したものをPBOに読み込み,
グレイスケール化後再描画を行うものを示します.
再描画にはglDrawPixelsを使うこともできますが,
ここではテクスチャを使っています.

#code(C){{
/*!
 * PBOによる画像処理
 */
void ProcessImage(void)
{
	// フレームバッファの内容をPBOに転送
	glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, g_iPBOSrc);	// PBOをアクティブにする
	glReadPixels(0, 0, g_iWinW, g_iWinH, GL_BGRA, GL_UNSIGNED_BYTE, 0); 	// 描画をPBOにロード

	// PBOの内容を編集
	GLubyte *ptr = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE);
	if(ptr){
		for(int i = 0; i < g_iWinW*g_iWinH; ++i){
			GLubyte gray = (GLubyte)((ptr[4*i]+ptr[4*i+1]+ptr[4*i+2])/3.0);
			ptr[4*i]   = gray;
			ptr[4*i+1] = gray;
			ptr[4*i+2] = gray;
		}
		glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
	}
	glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);

	// PBOからテクスチャへ転送
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, g_iPBOSrc);

	glBindTexture(GL_TEXTURE_2D, g_iTexScreen);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_iWinW, g_iWinH, GL_BGRA, GL_UNSIGNED_BYTE, 0);

	glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
}

/*!
 * 画像の描画
 */
void RenderImage(void)
{
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);
	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

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

	glMatrixMode( GL_MODELVIEW);
	glLoadIdentity();

	glViewport(0, 0, g_iWinW, g_iWinH);
	
	glBindTexture(GL_TEXTURE_2D, g_iTexScreen);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 1.0);	glVertex3f(-1.0,  1.0, 0.5);
	glTexCoord2f(1.0, 1.0);	glVertex3f( 1.0,  1.0, 0.5);
	glTexCoord2f(1.0, 0.0);	glVertex3f( 1.0, -1.0, 0.5);
	glTexCoord2f(0.0, 0.0);	glVertex3f(-1.0, -1.0, 0.5);
	glEnd();

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glDisable(GL_TEXTURE_2D);

	glutSwapBuffers();
}
}}

g_iWinW,g_iWinHは描画領域の大きさで,g_iTexScreenは描画領域と同じ大きさのテクスチャです.
描画時にはシーン描画関数を呼び出した後,上記関数を連続して呼び出します.

#code(C){{
void Display(void)
{
	RenderScene();	// シーン描画
	ProcessImage();	// PBOへの転送と編集
	RenderImage();	// 編集したものをテクスチャで描画
}
}}

シーンの例として,

#code(C){{
/*!
 * シーン描画
 */
void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

	// 図形の描画
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glDisable(GL_CULL_FACE);
	glEnable(GL_LIGHTING);

	glPushMatrix();
	glColor3f(0.0, 0.0, 1.0);
	glutSolidTeapot(1.0);
	glPopMatrix();

	glPopMatrix();

	glFlush();
}
}}

で行った描画結果を以下に示します.

#ref(teapot_gray_1.jpg)

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS