How to take screenshot in OpenGL

前端 未结 7 705
终归单人心
终归单人心 2020-12-01 04:59

How to take a screenshot of an OpenGL window in C++ and save it to file.

I found the glReadPixels() function, but I don\'t know what to do next. Where I can set path

相关标签:
7条回答
  • 2020-12-01 05:32

    Runnable example

    Each time you click with the mouse on the window, a tmpX.ppm file is created with the current screenshot.

    You can view this file for example with eog on Linux, and inspect it with a text editor.

    To render without showing a window, see: How to use GLUT/OpenGL to render to a file?

    #include <math.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #define GL_GLEXT_PROTOTYPES 1
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include <GL/glut.h>
    #include <GL/glext.h>
    
    static GLubyte *pixels = NULL;
    static const GLenum FORMAT = GL_RGBA;
    static const GLuint FORMAT_NBYTES = 4;
    static const unsigned int HEIGHT = 500;
    static const unsigned int WIDTH = 500;
    static unsigned int nscreenshots = 0;
    static unsigned int time;
    
    /* Model. */
    static double angle = 0;
    static double angle_speed = 45;
    
    static void init(void)  {
        glReadBuffer(GL_BACK);
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
        glViewport(0, 0, WIDTH, HEIGHT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
    
        pixels = malloc(FORMAT_NBYTES * WIDTH * HEIGHT);
        time = glutGet(GLUT_ELAPSED_TIME);
    }
    
    static void deinit(void)  {
        free(pixels);
    }
    
    static void create_ppm(char *prefix, int frame_id, unsigned int width, unsigned int height,
            unsigned int color_max, unsigned int pixel_nbytes, GLubyte *pixels) {
        size_t i, j, k, cur;
        enum Constants { max_filename = 256 };
        char filename[max_filename];
        snprintf(filename, max_filename, "%s%d.ppm", prefix, frame_id);
        FILE *f = fopen(filename, "w");
        fprintf(f, "P3\n%d %d\n%d\n", width, HEIGHT, 255);
        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                cur = pixel_nbytes * ((height - i - 1) * width + j);
                fprintf(f, "%3d %3d %3d ", pixels[cur], pixels[cur + 1], pixels[cur + 2]);
            }
            fprintf(f, "\n");
        }
        fclose(f);
    }
    
    static void draw_scene() {
        glClear(GL_COLOR_BUFFER_BIT);
        glLoadIdentity();
        glRotatef(angle, 0.0f, 0.0f, -1.0f);
        glBegin(GL_TRIANGLES);
        glColor3f(1.0f, 0.0f, 0.0f);
        glVertex3f( 0.0f,  0.5f, 0.0f);
        glColor3f(0.0f, 1.0f, 0.0f);
        glVertex3f(-0.5f, -0.5f, 0.0f);
        glColor3f(0.0f, 0.0f, 1.0f);
        glVertex3f( 0.5f, -0.5f, 0.0f);
        glEnd();
    }
    
    static void display(void) {
        draw_scene();
        glutSwapBuffers();
        glReadPixels(0, 0, WIDTH, HEIGHT, FORMAT, GL_UNSIGNED_BYTE, pixels);
    }
    
    static void idle(void) {
        int new_time = glutGet(GLUT_ELAPSED_TIME);
        angle += angle_speed * (new_time - time) / 1000.0;
        angle = fmod(angle, 360.0);
        time = new_time;
        glutPostRedisplay();
    }
    
    void mouse(int button, int state, int x, int y) {
        if (state == GLUT_DOWN) {
            puts("screenshot");
            create_ppm("tmp", nscreenshots, WIDTH, HEIGHT, 255, FORMAT_NBYTES, pixels);
            nscreenshots++;
        }
    }
    
    int main(int argc, char **argv) {
        GLint glut_display;
        glutInit(&argc, argv);
        glutInitWindowSize(WIDTH, HEIGHT);
        glutInitWindowPosition(100, 100);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
        glutCreateWindow(argv[0]);
        init();
        glutDisplayFunc(display);
        glutIdleFunc(idle);
        glutMouseFunc(mouse);
        atexit(deinit);
        glutMainLoop();
        return EXIT_SUCCESS;
    }
    

    Compile with:

    gcc main.c -lm -lGL -lGLU -lglut
    

    Tested on Ubuntu 15.10, OpenGL 4.5.0 NVIDIA 352.63.

    Vulkan

    This example just worked: https://github.com/SaschaWillems/Vulkan/blob/b9f0ac91d2adccc3055a904d3a8f6553b10ff6cd/examples/screenshot/screenshot.cpp how to run it: Is it possible to do offscreen rendering without Surface in Vulkan?

    0 讨论(0)
提交回复
热议问题