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)