在java OpenGL中从屏幕(视口)导出图像
我是OpenGL编程的新手。我正在用OpenGL制作一个java程序。我在里面画了很多立方体。我现在想在我的程序中实现一个屏幕截图功能,但我就是不能让它工作。情况如下:在java OpenGL中从屏幕(视口)导出图像,java,opengl,jogl,Java,Opengl,Jogl,我是OpenGL编程的新手。我正在用OpenGL制作一个java程序。我在里面画了很多立方体。我现在想在我的程序中实现一个屏幕截图功能,但我就是不能让它工作。情况如下: 我使用FPSanimator以60 fps刷新了我的绘图 我在显示器里画了几十个立方体 我在面板中添加了一个KeyListener,如果我按下alt键,程序将运行以下方法: public static void exportImage() { int[] bb = new int[Constants.PanelSize
- 我使用FPSanimator以60 fps刷新了我的绘图
- 我在显示器里画了几十个立方体
- 我在面板中添加了一个KeyListener,如果我按下alt键,程序将运行以下方法:
public static void exportImage() { int[] bb = new int[Constants.PanelSize.width*Constants.PanelSize.height*4]; IntBuffer ib = IntBuffer.wrap(bb); ib.position(0); Constants.gl.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1); Constants.gl.glReadPixels(0,0,Constants.PanelSize.width,Constants.PanelSize.height,GL2.GL_RGBA,GL2.GL_UNSIGNED_BYTE,ib); System.out.println(Constants.gl.glGetError()); ImageExport.savePixelsToPNG(bb,Constants.PanelSize.width,Constants.PanelSize.height, "imageFilename.png"); } // Constant is a class which I store all my global variables in static type
- 控制台中的输出为0,这意味着没有错误。我在缓冲区中打印了内容,它们都是零
- 我检查了输出文件,它只有1kB李>
我该怎么办?有没有什么好的建议让我使用OpenGL将屏幕内容导出到图像文件中?我听说有好几个图书馆,但我不知道哪一个合适。非常感谢您的帮助(如果我有任何语法错误,请原谅我…您可以使用Robot类截图:
BufferedImage screenshot = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(screenshot, "png", new File("screenshot.png"));
有两件事需要考虑:
从屏幕上截取屏幕快照,可以确定视口的坐标位置,因此只能捕捉感兴趣的部分
有些东西可能驻留在视口的顶部(另一个窗口),因此视口可能被另一个窗口隐藏,这不太可能发生,但可以发生。在LWJGL中使用缓冲区时,几乎总是需要直接分配缓冲区。OpenGL库并不真正理解如何与Java数组接口™, 为了使底层内存操作正常工作,需要将它们应用于本机分配(或者,在本文中,直接分配)的内存 如果您使用的是LWJGL 3.x,这非常简单:
//Check the math, because for an image array, given that Ints are 4 bytes, I think you can just allocate without multiplying by 4.
IntBuffer ib = org.lwjgl.BufferUtils.createIntBuffer(Constants.PanelSize.width * Constants.PanelSize.height);
如果该功能不可用,这就足够了:
//Here you actually *do* have to multiply by 4.
IntBuffer ib = java.nio.ByteBuffer.allocateDirect(Constants.PanelSize.width * Constants.PanelSize.height * 4).asIntBuffer();
然后你做你的普通代码:
Constants.gl.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1);
Constants.gl.glReadPixels(0, 0, Constants.PanelSize.width, Constants.PanelSize.height, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, ib);
System.out.println(Constants.gl.glGetError());
int[] bb = new int[Constants.PanelSize.width * Constants.PanelSize.height];
ib.get(bb); //Stores the contents of the buffer into the int array.
ImageExport.savePixelsToPNG(bb, Constants.PanelSize.width, Constants.PanelSize.height, "imageFilename.png");
假设正在绘制默认帧缓冲区,则可以执行以下操作:
protected void saveImage(GL4 gl4, int width, int height) {
try {
GL4 gl4 = GLContext.getCurrentGL().getGL4();
BufferedImage screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = screenshot.getGraphics();
ByteBuffer buffer = GLBuffers.newDirectByteBuffer(width * height * 4);
gl4.glReadBuffer(GL_BACK);
gl4.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++) {
graphics.setColor(new Color((buffer.get() & 0xff), (buffer.get() & 0xff),
(buffer.get() & 0xff)));
buffer.get();
graphics.drawRect(w, height - h, 1, 1);
}
}
BufferUtils.destroyDirectBuffer(buffer);
File outputfile = new File("D:\\Downloads\\texture.png");
ImageIO.write(screenshot, "png", outputfile);
} catch (IOException ex) {
Logger.getLogger(EC_DepthPeeling.class.getName()).log(Level.SEVERE, null, ex);
}
}
受保护的void saveImage(GL4 GL4,整数宽度,整数高度){
试一试{
GL4 GL4=GLContext.getCurrentGL().getGL4();
BuffereImage屏幕截图=新的BuffereImage(宽度、高度、BuffereImage.TYPE_INT_RGB);
Graphics Graphics=屏幕截图.getGraphics();
ByteBuffer buffer=GLBuffers.newDirectByteBuffer(宽*高*4);
gl4.glReadBuffer(GL_BACK);
gl4.glReadPixels(0,0,宽度,高度,GL_RGBA,GL_无符号字节,缓冲区);
对于(int h=0;h
实际上,您创建了一个BuffereImage和一个direct buffer。然后使用Graphics
将后缓冲区的内容逐像素渲染到BuffereImage。
您需要一个额外的缓冲区
因为它表示alpha值,您还需要height-h
来翻转图像
编辑:当然,当有你想要的东西时,你需要阅读它
您有几个选择:
- 触发一个布尔变量,并直接从
方法调用它,最后,当您想要的一切都呈现出来时display
- 禁用自动缓冲区交换,从按键侦听器调用
方法,读取后缓冲区并再次启用交换display()
- 从键侦听器调用与在显示器中调用相同的代码
常量
I图像,您正在其中存储gl
对象?如果是,你应该避免它,因为它是非常危险的。如果要获取它,请使用GL4 GL4=GLContext.getCurrentGL().getGL4()代码>我明白了。我会换的。它有多危险?我这样做只是为了在类之间共享对象,以便轻松地分离作业,就像很多事情一样。因为它可能会在没有建议的情况下在不同的帧之间更改,并且您可能会发现自己在一些无效的位置启动命令。您有两种选择:从AutoDrawable
中获取它并将其传递给所有方法,或者从GLContext
中获取它。我认为它与OpenGl设置有关。在我读取像素之前,是否需要进行任何特殊设置?我实现了该方法,但图像完全是黑色的。我认为OpenGL只读取背景。我应该在哪里调用该方法?(为了确保OpenGL在绘制对象后读取像素),我实现了您的第一个建议,它成功了。非常感谢:)听到这个消息我很高兴,好极了:)