とある事情で、OpenGLを使ったオフスクリーンレンダリング(ウインドウではなくメモリ上への描画)の方法を調べていたのですが、OpenGLに関するネット上のサンプルはfreeglutなどの補助ライブラリを使う方法ばかり…。
freeglutは初期化の時点でウインドウの作成が必須になるので、いわゆる「オンスクリーンレンダリング」となってしまい目的に合いません。まぁ、グラフィックライブラリだからウインドウがある前提なのは当たり前なのですが…(´・ω・)
あれやこれやと苦労した結果、ようやくウインドウを作らずにレンダリングする方法が分かったので、サンプルコードとして残しておこうと思います。
作成したサンプルコード
以下が作成したサンプルコードです。VisualStudio2017上で作ったものですが、おそらく古いバーションでも動くかと思います。
一部でOpenCVの関数を叩いていますが、これはレンダリング結果を画像として保存するためです。レンダリング自体にOpenCVは必要ありません。ちなみに、エラー処理などは入れてないので安全な動作は一切保証してません。参考にされる際はすべて自己責任でどうぞm(_ _)m
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "opencv_core330.lib")
#pragma comment(lib, "opencv_highgui330.lib")
#pragma comment(lib, "opencv_imgcodecs330.lib")
#pragma comment(lib, "opencv_imgproc330.lib")
#include <Windows.h>
#include <gl/GL.h>
#include "opencv/cv.hpp"
#define WIDTH 1000
#define HEIGHT 1000
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
24,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0,
};
BITMAPINFO bmi = {
{
sizeof(BITMAPINFOHEADER),
WIDTH,
HEIGHT,
1,
32,
BI_RGB,
0, 0, 0, 0, 0,
},
};
int main(void)
{
/* ハンドルデバイスコンテキスト(HDC)を作成 */
HDC hDC = CreateCompatibleDC(NULL);
/* 描画領域となるビットマップを作成 */
void *pvBits;
HBITMAP hBMP = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0);
/* HDCにビットマップを設定 */
SelectObject(hDC, hBMP);
/* ピクセルフォーマットを設定 */
int pixFormat = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, pixFormat, &pfd);
/* レンダリングコンテキスト(RC)を作成 */
HGLRC hRC = wglCreateContext(hDC);
/* RCを描画対象に設定 */
wglMakeCurrent(hDC, hRC);
/* OpenGLで描画 */
glBegin(GL_QUADS);
glColor3f(1.0, 0.0, 0.0);
glVertex2d(-0.5, -0.5);
glColor3f(0.0, 1.0, 0.0);
glVertex2d(-0.5, 0.5);
glColor3f(0.0, 0.0, 1.0);
glVertex2d(0.5, 0.5);
glColor3f(1.0, 1.0, 1.0);
glVertex2d(0.5, -0.5);
glEnd();
/* 描画したデータを取得 */
IplImage *img = cvCreateImage(cvSize(WIDTH, HEIGHT), 8, 4);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, img->imageData);
/* RGB->BGRに変換して画像保存 */
cvCvtColor(img, img, CV_RGBA2BGRA);
cvSaveImage("opengl.bmp", img);
wglMakeCurrent(NULL, NULL);
/* リソースの破棄 */
cvReleaseImage(&img);
wglDeleteContext(hRC);
DeleteObject(hBMP);
DeleteDC(hDC);
return 0;
}
このコードを実行すると、以下のような画像がファイルとして保存されます。GUIウインドウへの描画などは一切行っていないので、オフスクリーンレンダリングができていることがわかります(・∀・)
ポイントとしては、OpenGLで使うコンテキストをゼロから作ってあげることなのですが、そこらへんを解説するとすごく長くなるので、以下の記事に別でまとめました。
コードの中身の詳細を知りたい方は、そちらの方もぜひ覗いてみてくださいm(_ _)m
ではではノシ