Come fare screenshot in OpenGL

Come fare uno screenshot di una finestra OpenGL in C ++ e salvarlo su file.

Ho trovato la funzione glReadPixels() , ma non so cosa fare dopo. Dove posso impostare il percorso di un file, ad esempio?

Se non è difficile, scrivi il codice, per favore.

Questo pezzo di codice acquisisce la finestra OpenGL ed esporta in un file BMP. È necessario disporre della libreria FreeImage per eseguirlo.

 // Make the BYTE array, factor of 3 because it's RBG. BYTE* pixels = new BYTE[3 * width * height]; glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); // Convert to FreeImage format & save to file FIBITMAP* image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, 0x0000FF, 0xFF0000, 0x00FF00, false); FreeImage_Save(FIF_BMP, image, "C:/test.bmp", 0); // Free resources FreeImage_Unload(image); delete [] pixels; 

glReadPixels copierà i bit in un buffer di memoria fornito dall’utente. È necessario formattare manualmente i dati (nel formato immagine desiderato) e scriverli su disco dopo la restituzione di glReadPixels .

Esempio eseguibile

Ogni volta che si fa clic con il mouse sulla finestra, viene creato un file tmpX.ppm con lo screenshot corrente.

È ansible visualizzare questo file per esempio con eog su Linux e controllarlo con un editor di testo.

Per eseguire il rendering senza mostrare una finestra, vedere: Come usare GLUT / OpenGL per eseguire il rendering su un file?

 #include  #include  #include  #define GL_GLEXT_PROTOTYPES 1 #include  #include  #include  #include  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_UNPACK_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; } 

Compilare con:

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

Testato su Ubuntu 15.10, OpenGL 4.5.0 NVIDIA 352.63.

Salvare i dati in un file è qualcosa che devi fare da solo o utilizzare una libreria di terze parti per – OpenGL non ha tale funzionalità.

Windows .bmp è probabilmente il più semplice se stai cercando di farlo da solo – Wikipedia ha una buona spiegazione del formato del file . Altrimenti puoi usare librerie di salvataggio / caricamento di immagini: libpng, libjpeg, ecc. Per il controllo di basso livello, o devil (ce ne sono altre, ma questo è il mio preferito, ed è una libreria estremamente versatile che si abbina bene a GL) per livello “basta farlo” immagine I / O.

In generale, OpenGL non fornisce funzioni per salvare l’immagine. Penso che il modo più veloce e più semplice per farlo sia salvare. Formato PPM . Tuttavia, questo tipo di formato non è compresso, il che significa che le dimensioni del file sarebbero molto grandi. E può essere supportato solo da alcuni programmi al giorno d’oggi.

Preferisco salvare l’immagine in un file .png che è compresso, ma dà anche un’immagine lossless e supportata da molti browser. Per salvare OpenGL in formato .png, prima consiglio il PNGwriter . È abbastanza semplice e facile da usare. Ad esempio, per salvare un pixel di un’immagine con il colore (R, G, B) nella posizione (x, y), il codice sarà (vedi “quickstart” nel sito Web di PNGwriter):

 pngwriter PNG(width, height, 1.0, fileName); // "1.0" stand for the white background PNG.plot(x, y, R, G, B); PNG.close(); 

Nota che, dal momento che PNGwriter salva ogni pixel partendo dall’angolo in alto a sinistra dell’immagine, mentre l’array proviene da glReadPixels () parte dall’angolo in basso a sinistra della finestra, il tuo codice per salvare l’intera immagine probabilmente sarà simile a questo :

 GLfloat* pixels = new GLfloat[nPixels]; glReadPixels(0.0, 0.0, width, height,GL_RGB, GL_FLOAT, pixels); pngwriter PNG(width, height, 1.0, fileName); size_t x = 1; size_t y = 1; double R, G, B; for(size_t i=0; i(pixels[i]); break; case 1: G = static_cast(pixels[i]); break; case 0: R = static_cast(pixels[i]); PNG.plot(x, y, R, G, B); // set pixel to position (x, y) if( x == width ) // Move to the next row of image { x=1; y++; } else // To the next pixel { x++; } break; } } PNG.close();