【问题标题】:Taking a screenshot with JOGL用 JOGL 截图
【发布时间】:2016-09-26 23:32:08
【问题描述】:

我正在寻找一种在没有awt Robot 的情况下以编程方式截取我的GLCanvas 的方法。

这是我目前的设置:

构造函数:

glcaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
glcaps.setDoubleBuffered(true);
glcaps.setHardwareAccelerated(true);

glcanvas = new GLCanvas(glcaps);
glcanvas.setSize(720, 720);
glcanvas.addGLEventListener(this);

glcanvas 被声明为实例变量:GLCanvas glcanvas

OpenGL 初始化:

@Override
public void init(GLAutoDrawable glad) {

    GL2 gl = glad.getGL().getGL2();
    glu = new GLU();

    gl.glEnable(GL2.GL_DEPTH_TEST);
    gl.glDepthFunc(GL2.GL_LEQUAL);
    gl.glShadeModel(GL2.GL_SMOOTH);
    gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
    gl.glClearColor(0f, 0f, 0f, 1f);

    // Some camera related code not shown
}

OpenGL 显示:

public void display(GLAutoDrawable glad) {
    GL2 gl = glad.getGL().getGL2();

    gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

    ...
    // Orient camera and draw a simple cube
    ...

    gl.glFlush();
}

截图方式:

BufferedImage b = new BufferedImage(glcanvas.getWidth(), glcanvas.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = b.createGraphics();
glcanvas.setupPrint(glcanvas.getWidth(), glcanvas.getWidth(), 50, 50, 50);
glcanvas.print(g);

try {
    ImageIO.write(b, "png", new File("test.png"));
} catch (IOException ex) {
    // Error handling
}

glcanvas.releasePrint();
g.dispose();

此方法有效,因为执行时不会崩溃,但是我得到的 png 文件只是黑色的,没有立方体。我也尝试使用 glReadPixels 但这也不起作用,因为它只是给了我一个充满 0 的缓冲区(黑色)。

我认为问题在于我没有从绘图线程中读取glcanvas。这是错误吗?如果是,我该如何解决?

感谢所有答案!

【问题讨论】:

  • 我认为glReadPixels 是正确的答案。
  • @immibis 当我使用glReadPixels 时,我仍然得到所有字节为0 并且图像变为黑色,即使在实际glcanvas 上渲染了一个立方体。我正在使用 displayinit 之外的不同方法执行 glReadPixels
  • 使用我的建议:forum.jogamp.org/… JOGL 2.3.2 可以正常工作:jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/com/…

标签: java opengl screenshot jogl glcanvas


【解决方案1】:

首先,您必须确保在您要捕获的内容被渲染后读取帧缓冲区。

其次,你可以这样做:

protected void saveImage(GL3 gl3, int width, int height) {

    try {
        BufferedImage screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphics = screenshot.getGraphics();

        ByteBuffer buffer = GLBuffers.newDirectByteBuffer(width * height * 4);
        // be sure you are reading from the right fbo (here is supposed to be the default one)
        // bind the right buffer to read from
        gl3.glReadBuffer(GL_BACK);
        // if the width is not multiple of 4, set unpackPixel = 1
        gl3.glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

        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..+ ", "
                graphics.setColor(new Color((buffer.get() & 0xff), (buffer.get() & 0xff),
                        (buffer.get() & 0xff)));
                buffer.get();   // consume alpha
                graphics.drawRect(w, height - h, 1, 1); // height - h is for flipping the image
            }
        }
        // This is one util of mine, it make sure you clean the direct buffer
        BufferUtils.destroyDirectBuffer(buffer);

        File outputfile = new File("D:\\Downloads\\texture.png");
        ImageIO.write(screenshot, "png", outputfile);
    } catch (IOException ex) {
    }
}

我在里面填写了一些评论,如果还有什么不清楚的地方,请不要犹豫进一步询问

【讨论】:

  • 这是我实现的,但我忘记在display() 中添加方法调用,因为我没有在正确的上下文中,所以它不起作用。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 2012-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多