Posted by
c0d3x on
Jul 18, 2019; 3:32pm
URL: https://forum.jogamp.org/offscreen-rendering-and-taking-screenshot-tp4039872.html
Hi there,
i am trying to take a screenshoot by offscreen rendering to some fbo, but it does not work as i expect.
i want to get this

but i got this

the code iam using is
package wigl.core.rendering;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL2ES3;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.util.GLBuffers;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import static com.jogamp.opengl.GL.*;
import static com.jogamp.opengl.GL.GL_UNSIGNED_BYTE;
import static com.jogamp.opengl.GL2ES3.GL_DEPTH_STENCIL_ATTACHMENT;
public class OffscreenRenderer {
private byte[] bbuffer;
private ByteBuffer glbuffer;
int[] fbo;
int[] texture;
int[] renderBuffer;
int width;
int height;
public OffscreenRenderer(GL2 gl, int w, int h) {
fbo = new int[1];
texture = new int[1];
renderBuffer = new int[1];
width = height = 0;
gl.glGenFramebuffers(1, fbo, 0);
gl.glGenTextures(1, texture, 0);
gl.glGenRenderbuffers(1, renderBuffer, 0);
setFrameSize(w, h);
}
public void setFrameSize(int w, int h) {
width = w;
height = h;
bbuffer = new byte[width * height * 3];
glbuffer = GLBuffers.newDirectByteBuffer(bbuffer);
}
public void render(GLRenderer renderer, GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
drawable.getContext().makeCurrent();
gl.glViewport(0, 0, width, height);
renderer.setViewport(width, height);
gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, fbo[0]);
gl.glActiveTexture(GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, texture[0]);
gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null);
gl.glPixelStorei(GL_UNPACK_ALIGNMENT,1);
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[0], 0);
gl.glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer[0]);
gl.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer[0]);
int[] buffers = {GL_COLOR_ATTACHMENT0};
gl.glDrawBuffers(1, buffers, 0);
renderer.draw(drawable.getGL().getGL2ES3());
gl.glFlush();
gl.glFinish();
glbuffer.rewind();
gl.glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, glbuffer);
gl.glFlush();
gl.glFinish();
gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0);
drawable.getContext().release();
}
public void saveCurrentBuffer(String path, GLAutoDrawable drawable) {
BufferedImage screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = screenshot.getGraphics();
glbuffer.rewind();
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
// The color are the three consecutive bytes, it's like referencing
// to the next consecutive array elements, so we got red, green, blue..
// red, green, blue, and so on...
// the boolean bitise and converts byte to unsigned byte, that actually not exists in java language
//graphics.setColor(new Color(glbuffer.get()& 0xFF, glbuffer.get()& 0xFF, glbuffer.get()& 0xFF));
int r = glbuffer.get() & 0xFF;
int g = glbuffer.get() & 0xFF;
int b = glbuffer.get() & 0xFF;
graphics.setColor(new Color(r, g, b));
graphics.drawRect(w, height - h - 1, 1, 1); // height - h is for flipping the image
}
}
try {
ImageIO.write(screenshot, "jpg", new File(path));
} catch (IOException e) {
e.printStackTrace();
}
}
public void dispose(GL2 gl) {
fbo = null;
texture = null;
gl.glDeleteTextures(1, texture, 0);
gl.glDeleteRenderbuffers(1, renderBuffer, 0);
gl.glDeleteFramebuffers(1, fbo, 0);
}
}
called as
public void takeScreenShoot(String path, GLAutoDrawable drawable) {
// render screen shot
offscreenRenderer.render(renderer, drawable);
// render visdibile frame
renderer.setViewport(getWidth(), getHeight());
drawable.getGL().getGL2().glViewport(0, 0, getWidth(), getHeight());
display();
offscreenRenderer.saveCurrentBuffer(path, drawable);
}
where the GLAutoDrawable is created as
GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
drawable = factory.createDummyAutoDrawable(null, true, caps, null);
i think its a problem with the depth buffer, the gl call routines in this sequence work in C++ but not in jogl/java. Please help, i have no idea where to go.
thank you very much for advice :)