我正在尝试将OpenGL场景渲染为图像,而不渲染到任何窗口。为了在OpenGL中进行渲染调用,我仍然需要一个窗口句柄来初始化GL上下文。因此,我通过GetDC(0)
将GL上下文绑定到"默认窗口句柄",生成的图像看起来很好。但是,使用"默认窗口句柄"的问题在于当呈现调用发生时整个屏幕 Flink 。
命令发送后,场景被渲染,在交换缓冲区之前,我通过glReadPixels
将场景保存为128x128的图像。注意,视口也被设置为0, 0, 128, 128
。
由于无法摆脱恼人的屏幕 Flink ,我决定为GL上下文创建一个虚拟窗口。这就是我如何做到的:
// Initialize Dummy Window custom class
WNDCLASSEX wincl{0};
wincl.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wincl.lpszClassName = _T("GLDummyWCL");
wincl.lpfnWndProc = WinProc;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
RegisterClassEx(&wincl);
// Initialize dummy window and show it as HIDDEN
hDummyWindow = CreateWindowEx(
0,
wincl.lpszClassName,
_T("GLDummyWindow"),
WS_BORDER,
0,
0,
128,
128,
HWND_DESKTOP,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL
);
//SetWindowLong(hDummyWindow, GWL_STYLE, 0);
SetWindowLong(hDummyWindow, GWL_STYLE, GetWindowLong(hDummyWindow, GWL_STYLE) & ~(WS_CAPTION)); // Remove title bar
ShowWindow(hDummyWindow, SW_HIDE);
// Initialize OpenGL Context
unsigned int PixelFormat;
static PIXELFORMATDESCRIPTOR pfd;
HDC hDC = GetDC(hDummyWindow); // GetDC(0);
PixelFormat = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, PixelFormat, &pfd);
HGLRC hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
这是我的渲染函数的样子:
glViewport(0, 0, 128, 128);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Bind vertex arrays, uniforms, then render primitives
// ...
SaveSceneToImage();
SwapBuffers(hDC);
以及将3D场景保存为图像的功能
void SaveSceneToImage() {
unsigned char data[3 * 128 * 128 ] = {0};
glReadPixels(0, 0, 128, 128, GL_RGB, GL_UNSIGNED_BYTE, data);
// Save to file
// ...
}
当把GL上下文绑定到一个实际的窗口句柄时,屏幕 Flink 停止了。但是,一个新的问题出现了。
图像被裁剪。这是它应该看起来的样子。当使用GetDC(0)
时它的工作原理:
这就是结果:
看到它是如何向下移动的了吗?为什么会这样呢?我试着删除窗口的边框,但是即使删除所有的样式也无济于事。改变glViewport
和glReadPixels
中的视口参数也没有任何作用。例如,增加y
参数会进一步移动它。我也希望不必修改这些。
是否需要修改窗口的其他内容?
注意,窗口充当上下文的呈现转储,因为没有窗口就没有GL上下文。
而且,这是我唯一愿意用于"无窗口"上下文创建的方法。
1条答案
按热度按时间rqqzpn5f1#
我无法解释你所看到的转变,但我会提供一个替代解决方案:
事实上,你不能可靠地渲染到隐藏窗口。即使它是可见的,你也不能可靠地使用它做任何事情,除了渲染到屏幕上可见的部分。这是因为渲染到默认帧缓冲区时会发生“像素所有权测试”。
进行离屏渲染的正确方法是像您一样创建一个带有OpenGL上下文的虚拟窗口,然后创建一个帧缓冲对象(FBO),渲染到该FBO,并从那里检索数据。由于FBO完全根据您的规范进行分配,这很可能会解决您的问题。