Login  Register

offscreen rendering and taking screenshot

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