render and capture offscreen

Hello all -

I’m pretty new at this, so I may be lacking some fundamental understanding. I have a system that creates a GLCanvas, adds it to a frame, and animates nicely. I can even capture the image to a bitmap.

What I really want to do, though, is actually render and capture the image offscreen without ever displaying the fame. I have tried two things with no success:

  1. Simply don’t make the frame visible. In this case the background of my desktop gets drawn into the areas of the GLCanvas where my nice rendering is supposed to be.

  2. Create a pbuffer for offscreen rendering. I get the following exception

net.java.games.jogl.GLException: Method “wglChoosePixelFormatARB” not available

when I try the createOffscreenDrawable() method. Coincidently, canCreateOffscreenDrawable() returns true;

Is there a better way to do what I am trying to do? I just want to draw and capture the contents of a GLCanvas without ever displaying it on the screen.

Many thanks,
D. Naphtha

My understanding is that it is not possible to do right now. The "work-around’ is that you create a 0x0 canvas, add that to the existing UI and go from there.

For the 2nd part, this is a known bug in the public stable release. It’s corrected in the CVS version. If you don’t want to rebuild from source, and you are on a Win32 box, fire me a contact email i can send you a JAR to. The JAR size is 544K.

Hi,

although this thread is a little old I wanted to reference two threads about offscreen rendering which might be useful:
http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=jogl;action=display;num=1077239979;start=1#1
http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=jogl;action=display;num=1063387918;start=

Now what I’m interested in is the way you capture the image to a bitmap. My final goal is to export my animation (displayed on a GLCanvas) to different formats like .bmp and .avi. The Java Media Framework (JMF) seems to helpful there. But how did you do it, naphtha?

I’m curious about this as well. I’ve started looking at APIs for generating animations and the JMF seemed like a good option. I’ve also seen references for makempeg (interface for mpeg_encode) on Unix and ImageMagick for Windows. Anyone had any experience with any of these APIs?

Sean

I haven’t seen any good (i.e. simple) examples of offscreen rendering using pbuffers, but I have looked at methods for creating animations in Java. My suggestion is to use the Quicktime API from Apple. They have a nice API, a single jar, and a bunch of source code. One of the examples creates a short movie from a series of generated buffers. All you would have to do was get a series of image captures from a pbuffer to make this work.

At this point, my main hesitations with working with pbuffers are 1)I don’t even know if they will work, considering that everybody has questions and nobody has source (that they are willing to post), and 2)the docs suggest that pbuffers are very experimental and may be deprecated.

As an aside, I would love to see one of the JOGL gurus add a sample to the examples site in which the program simply creates a pbuffer, draws a single triangle, captures the buffer, and saves it to a file.

Me too shaddam_IV.

I add some more to your request: grab the pbusser and get a translucent image (not a fully opaque one).

see my bug report:
https://jogl.dev.java.net/issues/show_bug.cgi?id=93

Mik

I have a program that does all that save the file saving part but I am sure you can figure that out on your own. I will dig it up tonight and post it. Take a look at the source for GLJPanel to get an idea of how to pull the framebuffer off the videocard.

I’m not 100% sure of what you are looking for, but I think this snippet of code will allow you to write to a BufferedImage, which you can then save out to a file:


int[] view = new int[4];
gl.glGetIntegerv(GL.GL_VIEWPORT, view);
int w = view[2], h = view[3];
BufferedImage image = new BufferedImage( w, h, BufferedImage.TYPE_3BYTE_BGR );
DataBufferByte dbByte = (DataBufferByte)image.getRaster().getDataBuffer();

gl.glReadBuffer( GL.GL_FRONT );
gl.glReadPixels( 0, 0, w, h, GL.GL_BGR, GL.GL_UNSIGNED_BYTE, dbByte.getData() );
gl.glFlush();

If you put this in your display method, the image will be captured each loop.

Regards,
Daniel

[quote]I have a program . . .
[/quote]
Excellent!

[quote]I think this snippet of code will allow you to write to a BufferedImage
[/quote]
naptha, there are at least 4 isues with this method:

  1. Actually shouldn’t be an issue anymore, but back when you had no control over buffer swapping you couldn’t get at the back buffer.

  2. glReadPixels is very slow.

  3. glReadPixels may not give consistent behavior on different machines/implementations. For example, if you have a dialog box overlapping your panel when you do your capture, the dialog may be captured as well. I haven’t actually tried this with a JOGL program, but it always happens when you do it with a Win32 or MFC + OpenGL app.

  4. glReadPixels forces you to render an image no bigger than your current window dimensions. These dimensions typically translate to poor print quality. The beauty of pbuffers is that you can make your image as big as you want within practical limits.

Anyways, I thought some of you new to gl image capture would find this info useful.

Thanks, Daniel, for the snippet.
I have tried the “changed JPanel” method (from an above referenced thread) which (as I recognized later) was also posted by you. After some minor adaptations it works pretty well for me, so thanks for that code even more!

Stefan

Is someone correctly grabbing translucent ARGB images (i.e. no opaque black background) ?

The pbuffer example is called PBDemo on this page. There isn’t a whole lot to it. It does read from the framebuffer since that is the fastest way to get the data off the card. I tried rendering to a texture and then pulling the texture off the card but that was slower than using the framebuffer as the source.

I don’t believe you should be having any problems with the alpha channel/pbuffers. Do you have a simple test program?

You should modifty your example and try to create an INT_ARGB image…

The background will be opaque black and not transparent.

No, I get gray with a clear color of 0,0,0,.5. I uploaded the changed demo. Just a guess but did you make sure you requested an alpha channel? The default mode is for no alpha.

This thread seems to be diverging a bit, but my reply is to Shaddam.

[quote]2) glReadPixels is very slow.
[/quote]
I agree, I haven’t been thrilled with the performance either. However, do you know of a faster way? If so, could you tell me, please?

[quote]3) glReadPixels may not give consistent behavior…
[/quote]
I’m actually rendering offscreen, so this is not a problem. However, for the sake of personal edification, do you have a better method to get a onscreen image to a bitmap?

Regards,
Daniel

The PBufferDemo gives this error (win2k,ATI Radeon 7000,jdk1.4.2_04):

net.java.games.jogl.GLException: pbuffer creation error: wglCreatePbufferARB() failed: (Unknown error code 0)
at net.java.games.jogl.impl.windows.WindowsPbufferGLContext.createPbuffer(WindowsPbufferGLContext.java:279)
at net.java.games.jogl.impl.windows.WindowsOnscreenGLContext.makeCurrent(WindowsOnscreenGLContext.java:116)
at net.java.games.jogl.impl.GLContext.invokeGL(GLContext.java:232)
at net.java.games.jogl.GLCanvas.displayImpl(GLCanvas.java:186)
at net.java.games.jogl.GLCanvas.display(GLCanvas.java:74)
at JOGL.PBDemo.(PBDemo.java:48)
at JOGL.PBDemo.main(PBDemo.java:122)

Failure with ERROR_SUCCESS? Those are some quality drivers. I will test that program on a 7200 later today. Hopefully I can figure out what is wrong. Pbuffer support by ati and nvidia is lacking.

[quote]This thread seems to be diverging a bit, but my reply is to Shaddam.

I agree, I haven’t been thrilled with the performance either. However, do you know of a faster way? If so, could you tell me, please?

I’m actually rendering offscreen, so this is not a problem. However, for the sake of personal edification, do you have a better method to get a onscreen image to a bitmap?

Regards,
Daniel
[/quote]
For saving an image, glReadPixels is fine since the save operation is slow anyways.

My solution for image capture (back in the C++ world) was to get a pbuffer, render to it, call glReadPixels to get the buffer’s data, and then save it. If you have an on-screen image, just create a compatible pbuffer, rerender to the pbuffer, get the pbuffer’s pixels, then save. Pbuffers are the solution you want since you can make the image as large as you desire.

BTW - One issue is that objects associated with a specific context are not necessarily going to be present in your offscreen context (e.g. your textures may be unavailable). As I recall from a conversation I had with one of the JOGL guys at GDC (Was it Ken?), JOGL is designed to share display lists with derived contexts, so this shouldn’t be a problem. JOGL Gods, please confirm or deny this. Thanks.

As long as the pbuffer has the same pixel format as teh original canvas it will share resources.

I tried the PBDemo on an ati 7200, it creates the pbuffer but it is just a jumble of static. I will try to figure out what the deal is.

Hey GKW,

Thanks for the sample code. Unfortunately, when I try to run it on my Linux box (Fedora Core 1), I get the following:

Exception in thread “main” net.java.games.jogl.GLException: pbuffer creation error: glXChooseFBConfig() failed
at net.java.games.jogl.impl.x11.X11PbufferGLContext.createPbuffer(X11PbufferGLContext.java:179)
at net.java.games.jogl.impl.x11.X11OnscreenGLContext.makeCurrent(X11OnscreenGLContext.java:117)
at net.java.games.jogl.impl.GLContext.invokeGL(GLContext.java:203)
at net.java.games.jogl.GLCanvas.displayImpl(GLCanvas.java:186)
at net.java.games.jogl.GLCanvas.display(GLCanvas.java:74)
at PBDemo.(PBDemo.java:48)
at PBDemo.main(PBDemo.java:123)

Any idea as to what the problem is?