How can I generate a screenshot when glReadPixels

2019-07-19 22:43发布

I have a program which runs in a window using OpenGL (VS2012 with freeglut 2.8.1). Basically at every time step (run via a call to glutPostRedisplay from my glutIdleFunc hook) I call my own draw function followed by a call to glFlush to display the result. Then I call my own screenShot function which uses the glReadPixels function to dump the pixels to a tga file.

The problem with this setup is that the files are empty when the window gets minimised. That is to say, the output from glReadPixels is empty; How can I avoid this?

Here is a copy of the screenShot function I am using (I am not the copyright holder):

//////////////////////////////////////////////////
// Grab the OpenGL screen and save it as a .tga //
// Copyright (C) Marius Andra 2001              //
// http://cone3d.gz.ee  EMAIL: cone3d@hot.ee    //
//////////////////////////////////////////////////
// (modified by me a little)
int screenShot(int const num)
{
    typedef unsigned char uchar;
    // we will store the image data here
    uchar *pixels;
    // the thingy we use to write files
    FILE * shot;
    // we get the width/height of the screen into this array
    int screenStats[4];

    // get the width/height of the window
    glGetIntegerv(GL_VIEWPORT, screenStats);

    // generate an array large enough to hold the pixel data 
    // (width*height*bytesPerPixel)
    pixels = new unsigned char[screenStats[2]*screenStats[3]*3];
    // read in the pixel data, TGA's pixels are BGR aligned
    glReadPixels(0, 0, screenStats[2], screenStats[3], 0x80E0, 
    GL_UNSIGNED_BYTE, pixels);

    // open the file for writing. If unsucessful, return 1
    std::string filename = kScreenShotFileNamePrefix + Function::Num2Str(num) + ".tga";

    shot=fopen(filename.c_str(), "wb");

    if (shot == NULL)
        return 1;

    // this is the tga header it must be in the beginning of 
    // every (uncompressed) .tga
    uchar TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};
    // the header that is used to get the dimensions of the .tga
    // header[1]*256+header[0] - width
    // header[3]*256+header[2] - height
    // header[4] - bits per pixel
    // header[5] - ?
    uchar header[6]={((int)(screenStats[2]%256)),
    ((int)(screenStats[2]/256)),
    ((int)(screenStats[3]%256)),
    ((int)(screenStats[3]/256)),24,0};

    // write out the TGA header
    fwrite(TGAheader, sizeof(uchar), 12, shot);
    // write out the header
    fwrite(header, sizeof(uchar), 6, shot);
    // write the pixels
    fwrite(pixels, sizeof(uchar), 
    screenStats[2]*screenStats[3]*3, shot);

    // close the file
    fclose(shot);
    // free the memory
    delete [] pixels;

    // return success
    return 0;
}

So how can I print the screenshot to a TGA file regardless of whether Windows decides to actually display the content on the monitor?

Note: Because I am trying to keep a visual record of the progress of a simulation, I need to print every frame, regardless of whether it is being rendered. I realise that last statement is a bit of a contradiction, since I need to render the frame in order to produce the screengrab. To rephrase; I need glReadPixels (or some alternative function) to produce the updated state of my program at every step so that I can print it to a file, regardless of whether windows will choose to display it.

2条回答
疯言疯语
2楼-- · 2019-07-19 23:29

I would suggest keeping the last rendered frame stored in memory and updating this memory's contents whenever an update is called and there is actual pixel data in the new render. Either that or you could use the accum perhaps, though I cant quite recall how it stores older frames (it may just end up updating out so fast that it stores no render data as well.

Another solution might be to use a shader to manually render each frame and write the result to a file

查看更多
唯我独甜
3楼-- · 2019-07-19 23:36

Sounds like you're running afoul of the pixel ownership problem.

Render to a FBO and use glReadPixels() to slurp images out of that instead of the front buffer.

查看更多
登录 后发表回答