Pixel Buffer Objectについて

PBOとは

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

PBOの使い方

PBOの作成はVBOとほぼ同じです. ただし,glBindBufferなどに指定するtargetに

  • GL_PIXEL_PACK_BUFFER : ピクセルデータをPBOへ転送(glReadPixel, glGetTexImage)
  • 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作成,破棄関数例は以下.

/*!
 * 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使用例

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

/*!
 * 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は描画領域と同じ大きさのテクスチャです. 描画時にはシーン描画関数を呼び出した後,上記関数を連続して呼び出します.

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

シーンの例として,

/*!
 * シーン描画
 */
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();
}

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

teapot_gray_1.jpg

添付ファイル: fileteapot_gray.jpg 1208件 [詳細] fileteapot_gray_1.jpg 2414件 [詳細]

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