使用DevIL或SOIL保存openGL输出

时间:2013-06-28 17:54:15

标签: opengl devil soil

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

有关保存屏幕截图或导出opengl输出的想法吗?

3 个答案:

答案 0 :(得分:3)

试试这个:

#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;
}

答案 1 :(得分:0)

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

一些基本规则:

如果从常规窗口捕获屏幕截图,请从

中捕获它们
  • 在绘图完成之后但在缓冲区交换之前的后缓冲区(glReadPixels在管道中的所有绘制操作的冲洗和完成,因为它引入了同步点)

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

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

答案 2 :(得分:0)

虽然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轴)