3D モデルを取得して画像にレンダリングする簡単なプログラムを作成したいと考えています。OpenGL を使用して画像をレンダリングし、画像を表示するのではなく、画像を保持する変数に入れる方法はありますか? レンダリングしているものを見たくないので、保存したいだけです。OpenGLでこれを行う方法はありますか?
2 に答える
OpenGL を使用して画面に何かを描画する方法を知っていて、そのためにdrawStuffなどの関数を作成したと仮定しています。
まず最初に、最終的なレンダリングの大きさを決定する必要があります。ここでは、サイズが 512x512 の正方形を選択しています。2 のべき乗ではないサイズを使用することもできますが、簡単にするために、ここではこの形式に固執しましょう。時々、OpenGL はこの問題にうるさいです。
const int width = 512;
const int height = 512;
次に、オフスクリーン描画領域を作成するために 3 つのオブジェクトが必要です。user1118321が言ったように、これはフレームバッファオブジェクトと呼ばれます。
GLuint color;
GLuint depth;
GLuint fbo;
FBO には、カラー バッファーと深度バッファーが格納されます。また、画面のレンダリング領域にはこれらの 2 つのバッファーがありますが、画面に描画したくないため、それらを使用したくありません。FBO を作成するには、たとえば起動時に次のようなことを1 回だけ行う必要があります。
glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
最初に、ピクセルの色を格納するためのメモリ領域を作成し、ピクセルの深さを格納するためのメモリ領域を作成します (コンピューター グラフィックスでは、隠れた表面を削除するために使用されます)。最後に、基本的に両方への参照を保持する FBO にそれらを接続します。例として、6 つの呼び出しがある最初のブロックを考えてみましょう。
- glGenTexturesはテクスチャの名前を作成します。OpenGL の名前は単純な整数です。文字列では効率が悪いからです。
- glBindTexture は、テクスチャをターゲット、つまりGL_TEXTURE_2Dにバインドします。同じターゲットを指定する後続の呼び出しは、そのテクスチャで動作します。
- 3 番目、4 番目、5 番目の呼び出しは操作対象に固有のものであり、詳細については OpenGL のドキュメントを参照してください。
- glBindTexture への最後の呼び出しは、テクスチャをターゲットからバインド解除します。ある時点で制御をdrawStuff関数に渡し、その関数が OpenGL 呼び出しを大量に行うため、作成したオブジェクトとの干渉を避けるために、ここでワークスペースをクリアする必要があります。
スクリーン レンダリングからオフスクリーン レンダリングに切り替えるには、プログラムのどこかでブール変数を使用できます。
if (offscreen)
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
else
glBindFramebuffer(GL_FRAMEBUFFER, 0);
drawStuff();
if (offscreen)
saveToFile();
したがって、offscreenがtrue の場合、実際にはdrawStuff がfboに干渉する必要があります。これは、 fboにシーンをレンダリングする必要があるためです。
関数 saveToFile は、レンダリングの結果をロードしてファイルに変換する役割を果たします。これは、使用している OS と言語に大きく依存します。例として、C を使用する Mac OS X では、次のようになります。
void saveImage()
{
void *imageData = malloc(width * height * 4);
glBindTexture(GL_TEXTURE_2D, color);
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
CGContextRef contextRef = CGBitmapContextCreate(imageData, width, height, 8, 4 * width, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGImageAlphaPremultipliedLast);
CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
CFURLRef urlRef = (CFURLRef)[NSURL fileURLWithPath:@"/Users/JohnDoe/Documents/Output.png"];
CGImageDestinationRef destRef = CGImageDestinationCreateWithURL(urlRef, kUTTypePNG, 1, NULL);
CGImageDestinationAddImage(destRef, imageRef, nil);
CFRelease(destRef);
glBindTexture(GL_TEXTURE_2D, 0);
free(imageData);
}
はい、できます。あなたがしたいことは、テクスチャに裏打ちされたフレーム バッファ オブジェクト (FBO)を作成することです。テクスチャを作成して描画したら、テクスチャをメイン メモリにダウンロードして、ビットマップと同じように保存できます。