我目前正在尝试使用glReadPixels在各种相机位置拍摄OpenGL渲染的3D世界的快照以及不同的图像分辨率。 我有两个select实现OpenGL Windows程序的GUI库:Qt和Freeglut。 经过两次实验之后,我意识到Qt不会将QGLWidget的快照图像分辨率限制为桌面大小,但对于FreeGlut则无法做到这一点。
我希望我可以使用Qt来抓取这个抓图程序,但是由于我的项目团队伙伴正在使用同一个程序的另一个模块,所以我不能花时间学习一个新库和IDE(Qt Creator)。 他正在使用Visual Studio 2008。
是否有我创build一个不受桌面大小限制的大小窗口,可以大到4000 x 2000?
经过两次实验之后,我意识到Qt不会将QGLWidget的快照图像分辨率限制为桌面大小,但对于FreeGlut则无法做到这一点。
被警告:如果您创建的窗口大于桌面,那些不在视图中的像素不能通过像素所有权测试。 因此,这些像素的内容是不确定的 。 他们可能包含你想要的,但他们可能不是。
对于任何不可见的像素来说都是如此,无论窗口是刚刚离开桌面还是被另一个窗口覆盖。
无论如何,你不应该创建一个窗口大小的桌面。 你应该创建一个正常的窗口,并制作一个包含大颜色和深度渲染 缓冲区的framebuffer对象 。 把所有的渲染都放到这些离屏缓冲区中。 那么你将不必担心窗口的大小限制。
用OpenGL做高分辨率渲染是有点棘手的。 一个问题是,像素所有权测试会阻碍。 另一个是帧缓冲区(对象)的最大尺寸。 第一个问题可以通过使用framebuffer对象或PBuffer来解决。
第二个需要一些技巧:假设我们要渲染一个大小为W×H的图像,其中W和H超过最大帧缓冲区大小; 标记GL_MAX_VIEWPORT_SIZE,GL_MAX_TEXTURE_SIZE,GL_MAX_RENDERBUFFER_SIZE的glGetInteger给出了这些限制。 所以你必须做的是将目标图像分割成小于这些限制的图块,渲染这些图块然后重新组合它们。 假设W_t和H_t是瓦片大小, W_t := W / N
, H_t := H / M
并且我们有相应大小的PBuffer或Framebuffer对象。 然后我们可以用2个循环渲染这些图块:
for m in 0 to M: for n in 0 to N: render_tile(n, m)
那么render_tile(n,m)
怎么样的呢?
render_tile(n,m):
显然我们使用整个瓦片作为渲染缓冲区
glViewport(0, 0, W_t, H_t)
所以投影有什么变化。 不知何故,我们必须将投影与投影平面中的瓦片一起移动。 投影平面也被称为“近”平面。 近平面的范围是right - left
和top - bottom
,所以我们把近平面分成大小(right - left) / N
× (top - bottom) / M
瓦片,这就是我们需要使用的移步长:
shift_X = (right - left) / N shift_Y = (top - bottom) / M glMatrixMode(GL_PROJECTION) glLoadIdentity() switch Projection: case Ortho: glOrtho( left + shift_X * n, left + shift_X * (n+1), bottom + shift_Y * m, bottom + shift_Y * (n+1), near, far) case Perspective: glFrustum( left + shift_X * n, left + shift_X * (n+1), bottom + shift_Y * m, bottom + shift_Y * (n+1), near, far) render_scene()
以防万一,我们如何得到left, right, top, bottom
的角度来看:
right = -0.5 * tan(fov) * near left = -right; top = aspect * right bottom = -top