7

I am currently trying to take snapshots of an OpenGL rendered 3D world at various camera positions and varying image resolution using glReadPixels. I have two choices for the GUI library that implements the OpenGL windows program: Qt and freeglut. After a few experiments on both, I realise that Qt does not limit the image resolution of its snapshots of a QGLWidget to the desktop size but I could not do the same for freeglut.

I wish I could use Qt for this snapshot grabbing program but I am limited to glut because my project team mate who is working on another module of the same program cannot afford the time to learn a new library and IDE (Qt Creator). He is using Visual Studio 2008.

Is there anyway for me to create a glut window that is not limited by the desktop size and can be as large as 4000 x 2000?

2 Answers 2

13

Doing high resolution renderings with OpenGL is a bit tricky. One problem is, that pixel ownership tests get in the way. The other are the maximum size for a framebuffer (object). The first problem can be overcome by using a framebuffer object or a PBuffer.

The second requires some trickery: Let's say we want to render an image of size W×H, where W and H exceed the maximum framebuffer size; glGetInteger of the tokens GL_MAX_VIEWPORT_SIZE, GL_MAX_TEXTURE_SIZE, GL_MAX_RENDERBUFFER_SIZE gives you those limits. So what you have to do is split up the target image into tiles smaller than those limits, render those tiles and then recombine them. Let's say W_t and H_t are the tile sizes, W_t := W / N, H_t := H / M and we have an accordingly sized PBuffer or Framebuffer object. Then we can render those tiles with a 2-loop:

for m in 0 to M: for n in 0 to N: render_tile(n, m) 

So how does render_tile(n,m) look like?

render_tile(n,m): 

Apparently we're using the whole tile as renderbuffer so

 glViewport(0, 0, W_t, H_t) 

so what changes is the projection. Somehow we've to shift the projection along with the tile in the projection plane. The projection plane is also known as the 'near' plane. The extents of the near plane are right - left and top - bottom, so we're splitting the near plane into tiles of size (right - left) / N×(top - bottom) / M so that's what we need to use as shift step size:

 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() 

And just in case how we get left, right, top, bottom for perspective:

right = -0.5 * tan(fov) * near left = -right; top = aspect * right bottom = -top 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the very detailed answer. I will look into FBO more and check if my needs exceed the GL_MAX_RENDERBUFFER_SIZE_EXT value on the machine performing this snapshot capturing task. Probably I would only need FBO-RenderBufferObject method. Thank you once again!
4

After a few experiments on both, I realise that Qt does not limit the image resolution of its snapshots of a QGLWidget to the desktop size but I could not do the same for freeglut.

Be warned: if you create a window that is larger than the desktop, those pixels that are not in view do not pass the pixel-ownership test. Therefore, the contents of those pixels is undefined. They may contain what you want, but they may not.

This is true for any pixels that are not visible, whether the window is just off the desktop or being covered by another window.

Anyway, you shouldn't be creating a window the size of your desktop. You should be creating a normal window, and making a framebuffer object that contains a large color and depth renderbuffer. Do all of your rendering to these off-screen buffers. Then you won't have to worry about size limitations of your window.

Though you will be limited by the maximum size of renderbuffers, as well as the maximum viewport size.

6 Comments

I have tested with Qt by placing a derived QGLWidget inside a QStackedWidget, adjust its size using spin buttons to around 3000 x 2500 and then use both glReadPixels and QGLWidget::RenderPixmap() to capture and save the screenshot of that QGLWidget. The QGLWidget is only partially visible on the GUI application but the screenshots saved are perfect. Seems like Qt handled the pixel-ownership test pretty well I think :) Your proposed solution is really interesting. My knowledge of OpenGL is still primitive basic fixed pipeline so I guess I need to read up more :)
Qt doesn't "handle" the pixel ownership test; it is defined by the OpenGL Specification, and it is handled at the Win32/X-Windows/graphics-driver/etc level, not the level that Qt operates at. If it worked for you, on this particular low-level windowing system, it is only because you got lucky. It should not be relied upon.
first link broken
@bluejayke: No, it's not. The link has certainly moved, but it will redirect you to the appropriate location.
So oddly, the first time I clicked the first link it gave me an official 404 page. After that the link worked...wtf
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.