要は、バッファのデータのコピー先となるBitmapオブジェクトを作成するわけです。
この辺は、とくにややこしいことは無いです。
画像の幅と高さ、フォーマットを指定して初期化するだけです。
// RGBAならFormat32bppArgb、RGBならFormat24bppRgb。 PixelFormat bmpPixelFormat = PixelFormat.Format32bppArgb; // Bitmapオブジェクトを作成。 // これにバッファのデータをコピーします。 Bitmap bmp = new Bitmap( width, height, bmpPixelFormat );
手順としては、
まず、BitmapDataというクラスを使ってBitmapのピクセルデータを直接いじれる状態に。
で、読み取るバッファをglReadBuffer(...)という関数で指定。
それから、OpenGLのglReadPixels(...)関数でバッファの内容をコピー。
が、注意点。
glReadPixels(...)の5つ目の引数で指定する値について。
取得したい色情報の形式を指定するわけだが、
RGBで取得したい場合は、GL_BGR、
RGBAで取得したい場合はGL_BGRAを指定しておくこと。
理由は、Windowsではメモリ上での各ピクセルの色情報の並び方がBRGとかBGRAの順になっているから。
ちなみに、これを間違えると、実行時にエラーがでるか、画像の色がヒドい事になります。
  // bmpの画像データを直接扱うために、こういうことをします。 // LockBits()メソッドを呼び出したら、あとで必ずUnlockBits()を呼び出す必要があります。 System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits( new Rectangle( 0, 0, bmp.Width, bmp.Height ), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmpPixelFormat ); // 読み取るOpneGLのバッファを指定。 // ここでは、バックバッファを読み取る。 // フロントバッファを読み取りたい場合は、GL_FRONT を指定する。 glReadBuffer( GL_BACK ); // バッファの内容を // bmpオブジェクトのピクセルデータが格納されている領域に直接コピーする。 glReadPixels( x, //読み取る領域の左下隅のx座標 y, //読み取る領域の左下隅のy座標 width, //読み取る領域の幅 height, //読み取る領域の高さ GL_BGRA, //取得したい色情報の形式 GL_UNSIGNED_BYTE, //読み取ったデータを保存する配列の型 bmpData.Scan0 //ビットマップのピクセルデータ(実際にはバイト配列)へのポインタ ); //LockBits()でロックしたものは、 //必ずUnlockBits()でアンロックすること。 bmp.UnlockBits( bmpData );
これで、バッファから読み取った画像がbmpオブジェクトに入っているはずです。
実は、もう一手間、必要だったりします。
このままでは、
OpenGLとWindowsでは画像の座標原点の位置が違う(OpenGLでは左下、Windowsでは左上。)ために、
bmpは上下逆さまな画像になっているので、
Bitmap.RotateFlip()
メソッドを使って上下を反転させます。
bmp.RotateFlip( RotateFlipType.RotateNoneFlipY );
これでOK。
あとは、Bitmap.Save()メソッドで、
ファイル名とかフォーマットとかを指定して、画像ファイルとして保存してやればOK。
ただし、画像ファイルのフォーマットには、ちょっと注意すべし。
ビットマップ形式(*.bmp)は、アルファチャンネルは保存できない、かつ、非圧縮なのでファイルサイズが大きい。
JPEG形式(*jpg)は、アルファチャンネルは保存できない、かつ、不可逆圧縮なので画像にちょっとだけノイズが混じる。
GIF形式(*.gif)は、256色のみ。うち一色を透明色として指定可能。
PNG形式(*.png)は、アルファチャンネルまで保存可能。しかし、色数が多いとJPEGよりファイルサイズが大きくなる傾向有り。
形式によってそれぞれ特徴があるので、場合によって使い分けるべし。
おすすめは、
アルファチャンネルが必要ない、または、あまり画質が良くなくても良いのであれば、JPEG、
アルファチャンネルが必要なら、PNG形式が適していると思います。