【问题标题】:Save openGL output using DevIL or SOIL使用 DevIL 或 SOIL 保存 openGL 输出
【发布时间】:2013-06-28 17:54:14
【问题描述】:

我尝试过使用土壤和恶魔图像库,但创建的屏幕截图是完全黑色的图像。对于魔鬼,我使用了这里找到的功能Take screenshot with openGL and save it as png,但图像仍然是黑屏。

关于保存屏幕截图或导出 opengl 输出的任何想法?

【问题讨论】:

  • 您是否对链接文章中提到的功能进行了任何修改?如果是这样,请发布您的代码。

标签: opengl devil soil


【解决方案1】:

试试这个:

#include <vector>
#include <GL/glut.h>
#include <SOIL/SOIL.h>

using namespace std;

bool save = false;
void display()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( -2, 2, -2, 2, -1, 1);

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glColor3ub( 255, 0, 0 );
    glBegin( GL_QUADS );
    glVertex2i( -1, -1 );
    glVertex2i(  1, -1 );
    glVertex2i(  1,  1 );
    glVertex2i( -1,  1 );
    glEnd();

    if( save )
    {
        int w = glutGet( GLUT_WINDOW_WIDTH );
        int h = glutGet( GLUT_WINDOW_HEIGHT );
        vector< unsigned char > buf( w * h * 3 );

        glPixelStorei( GL_PACK_ALIGNMENT, 1 );
        glReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buf[0] );

        int err = SOIL_save_image
            (
            "img.bmp",
            SOIL_SAVE_TYPE_BMP,
            w, h, 3,
            &buf[0]
            );

        save = false;
    }

    glutSwapBuffers();
}

void keyboard( unsigned char key, int x, int y )
{
    if( key == 's' ) 
    {
        save = true;
        glutPostRedisplay();
    }
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 640, 480 );
    glutCreateWindow( "GLUT" );
    glutDisplayFunc( display );
    glutKeyboardFunc( keyboard );
    glutMainLoop();
    return 0;
}

【讨论】:

  • 我试过这个功能,虽然效果很好,但是我得到的图像是颠倒的。知道为什么吗?
  • @pslayer89:哎呀,我应该测试一个没有垂直对称性的场景 :) 这就是从 OpenGL 中产生比特的方式。试试SOIL_SAVE_TYPE_BMP | SOIL_FLAG_INVERT_Y
  • @genpfault 这样做,它只是不保存任何图像:(
  • @pslayer89:你说得对,对不起,我应该更努力地阅读 SOIL 标题 :( 如果你愿意失去一些灵活性,看起来SOIL_save_screenshot() 会在内部翻转。
  • @genpfault 我之前实际上是在使用 SOIL_save_screenshot,但是当我尝试使用高于 1024 x 768 的分辨率捕获屏幕截图时,显然我的应用程序崩溃了。这就是为什么我正在寻找一个好的替代方案,并且我偶然发现了这篇文章。
【解决方案2】:

从 OpenGL 渲染保存屏幕截图时最大的问题是,常规系统窗口(通常用作 OpenGL 的绘图画布)的帧缓冲区是极其不可靠的数据源。如果它(部分)被其他窗口遮挡,则某些部分可能根本不包含任何定义的数据。缓冲区交换后,后台缓冲区的内容未定义,等等。

一些基本规则:

如果从常规窗口捕获屏幕截图,请从任一窗口中捕获它们

  • 在绘制完成后缓冲区交换之前的后台缓冲区(glReadPixels 意味着管道中所有绘制操作的刷新和完成,因为它引入了一个同步点)

  • 缓冲区交换后的前缓冲区

要获得可靠的 OpenGL 渲染捕获,您应该渲染到帧缓冲区对象。那里的图像定义明确,不会在窗口失效和动画循环或其他奇怪情况之间的一些难以跟踪和调试的竞争条件下“消失”。要显示图片,然后从 FBO 到主帧缓冲区。

【讨论】:

    【解决方案3】:

    虽然 genpfault 的回答做得很好,但它让我找到了一个更清洁的解决方案:

    if (!SOIL_save_screenshot("screenshot.bmp",
        SOIL_SAVE_TYPE_BMP, 0, 0, width, height)) {
        // Handle error here
    }
    

    这样您就不必设置缓冲区、调用glReadPixels 等。SOIL 可以自动为您处理所有这些!

    另外请注意,根据 genpfault 对 pslayer89 评论的回复,您需要将 SOIL_FLAG_INVERT_Y 添加到第二个参数中传递的标志中(除非您已经使用投影/模型矩阵反转 Y 轴)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-25
      • 1970-01-01
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 2013-02-06
      相关资源
      最近更新 更多