|
Pixel Buffer Objectについて PBOとは†Pixel Buffer Object(PBO)はVBOをピクセルデータを格納できるように拡張したものです. PBOではDMAを用いてビデオカードとのデータのやり取りを行うので,CPUサイクルに影響されずに 高速に転送できます.また,フレームバッファやテクスチャメモリとのデータのやり取りも 可能です(glReadPixels, glDrawPixels, glGetTexImage, glTexImage2D, glTexSubImage2Dなどを使用). PBOの使い方†PBOの作成はVBOとほぼ同じです. ただし,glBindBufferなどに指定するtargetに
また,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();
}
で行った描画結果を以下に示します. |