Question

I have tried using both soil and devil image libraries but the screenshots created are completely black images. For devil I used the function found here Take screenshot with openGL and save it as png but the image is still black screen.

Any ideas about saving screenshot or exporting opengl output?

Was it helpful?

Solution

Try this:

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

OTHER TIPS

The biggest problem when saving screenshots from OpenGL renderings is, that the framebuffer of a regular system Window (which you normally use as drawing canvas for OpenGL) is a extremely unreliable source for data. If it's (partially) occluded by other windows some parts may contain no defined data at all. After a buffer swap the contents of the back buffer are undefined, etc. etc.

A few basic rules:

If capturing screenshots from the regular window, capture them from either

  • the back buffer right after the drawing finished but before the buffer swap (glReadPixels implieas a flush and finish of all drawing operations in the pipeline, as it introduces a synchronization point)

  • the front buffer after the buffer swap

To get reliable captures of OpenGL renderings, you should render to a framebuffer object. There the image is well defined and will not "vanish" in some hard to trace and debug race conditions between window invalidations and animation loops or other weird situations. To display the picture you then blit from the FBO to the main framebuffer.

While genpfault's answer does the job nicely, it led me to a much cleaner solution:

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

This way you avoid having to set up a buffer, call glReadPixels, etc. SOIL can handle all of that for you automatically!

Also be aware that as per genpfault's response to pslayer89's comment, you need to add SOIL_FLAG_INVERT_Y to the flags passed in the second parameter (unless you're already inverting the Y-axis with your projection/model matrix).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top