Framebuffer in eine Datei sichern

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
HalcyonDays
Beiträge: 4
Registriert: 10.07.2012, 15:58
Echter Name: Tim
Wohnort: Aachen

Framebuffer in eine Datei sichern

Beitrag von HalcyonDays »

Hallo liebe Community,

ich habe ein für euch bestimmt simples Problem. Für eine Datensimulation müsste ich einzelne gerenderte Frames in Bilder schreiben. Dies habe ich in OpenGL wie folgt versucht:

Code: Alles auswählen

#include <GL/freeglut.h>
#include <cstring>
#include <iostream>
#include <tiffio.h>

const int windowWidth = 1300;
const int windowHeight = 800;

bool snapshotTIFF( const char *outFilename ) {

	GLubyte *imageBuffer = (GLubyte *)malloc( windowWidth * windowHeight * 4 );
	if( !imageBuffer ) {
		return false;
	}
	memset( imageBuffer, 0, windowWidth * windowHeight * 4 );

	TIFF *file = TIFFOpen(outFilename, "wb");
	if( file ) {
		glPixelStorei( GL_PACK_ALIGNMENT, 1 );
		glReadPixels( 0, 0, windowWidth, windowHeight, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer );

		TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) windowWidth);
		TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) windowHeight);
		TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8);
		TIFFSetField(file, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
		TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
		TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 4);
		TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
		TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1);
		TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, "");

		GLubyte *p = imageBuffer;
		for( int i = windowHeight - 1; i >= 0; i-- ) {
			if( TIFFWriteScanline(file, p, i, 0) < 0 ) {
				free(imageBuffer);
				TIFFClose(file);
				return false;
			}
		}
		p += windowWidth * sizeof(GLubyte) * 4 ;
	}
	TIFFClose(file);

	free( imageBuffer );
	return true;
}
void glutRenderingCallback() {
	glClearColor( 1.0f, 1.0f, 0.5f, 1.0f );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glLoadIdentity(); 

	glTranslatef( 0.0f, 0.0f, -5.0f );  
	glRotatef( 30.0f, 0.0f, 1.0f, 0.0f );
	glRotatef( 30.0f, 1.0f, 0.0f, 0.0f );
	glutSolidCube( 2.0f ); 

	glutSwapBuffers();
}

void glutReshapeCallback( int width, int height ) {  
	glViewport(0, 0, (GLsizei)width, (GLsizei)height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0);
	glMatrixMode(GL_MODELVIEW);
}

void glutKeyboardCallback( unsigned char key, int x, int y ) {
	switch( key ) {
		case 's':
			glReadBuffer( GL_FRONT );
			snapshotTIFF( "test_front.tif" );
			glReadBuffer( GL_BACK );
			snapshotTIFF( "test_back.tif" );
			std::cout << "Took snapshot!" << std::endl;
			break;
	}
}  

int main( int argc, char **argv ) {
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
	glutInitWindowSize( windowWidth, windowHeight );
	glutInitWindowPosition( 100, 100 );
	glutCreateWindow( "****** Simulation" );
	glEnable( GL_DEPTH_TEST );
	glEnable( GL_LIGHTING );
	glEnable( GL_LIGHT0 );
	glutDisplayFunc( glutRenderingCallback );
	glutReshapeFunc( glutReshapeCallback );
	glutKeyboardFunc( glutKeyboardCallback );
	glutMainLoop();
	return 0;
}
Das Problem ist nur, dass die Bilder die ich rausschreibe nur die Clear-Color enthalten, nicht aber den 3D Cube. Somit sollte ja die Methode zum erzeugen des Bilder korrekt funktionieren, aber das auslesen des Framebuffers wohl nicht. Könnte mir jemand von euch einen Tipp geben wo der Fehler hier liegen könnte? Wie gesagt: Ich würde eigentlich nur gerne den Inhalt des Framebuffers (also das was ich auch gerendert sehe) in Bilddateien schreiben.

Vielen Dank im Voraus.

Viele Grüße,
Tim
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Framebuffer in eine Datei sichern

Beitrag von CodingCat »

Bist du dir denn sicher, dass der Würfel im Framebuffer landet, also Kameratransformation etc. stimmen? Sprich, kannst du den Würfel im Fenster sehen?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
HalcyonDays
Beiträge: 4
Registriert: 10.07.2012, 15:58
Echter Name: Tim
Wohnort: Aachen

Re: Framebuffer in eine Datei sichern

Beitrag von HalcyonDays »

Hey,

japps, das ist ja das komische: Das OpenGL Fenster zeigt den Wuerfel an. Ich sehe einen gelblichen Hintergrund mit einem grauen Wuerfel. Sobald ich mir die Tiff-Datei ansehe, ist die nur komplett gelb. Kein Wuerfel zu sehen :(

Viele Gruesse,
Tim
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Framebuffer in eine Datei sichern

Beitrag von eXile »

Ich kenne mich mit der glut nicht gut aus, aber kann es sein, dass die glut zwischen glutKeyboardCallback und glutRenderingCallback vielleicht irgendwelchen Unfug mit dem Framebuffer macht? Soll heißen: Ändere es mal so, dass in glutKeyboardCallback eine globale Variable geändert wird, die anzeigt, dass im nächsten Aufruf von glutRenderingCallback der Framebuffer gespeichert werden soll, und rufe snapshotTIFF aus glutRenderingCallback auf.
joggel

Re: Framebuffer in eine Datei sichern

Beitrag von joggel »

Ich rate auch mal mit.

Also entweder das mal probieren was eXile meint.

Oder was ich mir auch vorstellen könnte, dass diese glutRenderingCallback in den Backbuffer rendert, und in der glutMainLoop lediglich glutSwapBuffers aufgerufen wird, um eben in das Fenster zu zeichnen (siehe double-buffering).
Also, du könntest dann auch in deiner snapshotTIFF den Quellbuffer, aus dem die Pixel gelesen werden sollen, mittels glReadBuffer(GL_BACK) angeben, und dann ganz normal deine glReadPixels durchführen.

Vorausgesetzt die Vermutung mit dem Back- und Frontbuffer trifft hier zu...
HalcyonDays
Beiträge: 4
Registriert: 10.07.2012, 15:58
Echter Name: Tim
Wohnort: Aachen

Re: Framebuffer in eine Datei sichern

Beitrag von HalcyonDays »

Hey,

die Idee war echt gut. Leider aber ohne Erfolg :cry: :

Code: Alles auswählen

#include <GL/freeglut.h>
#include <cstring>
#include <iostream>
#include <tiffio.h>

const int windowWidth = 1300;
const int windowHeight = 800;
bool takeSnapshot = false;

bool snapshotTIFF( const char *outFilename ) {

	GLubyte *imageBuffer = (GLubyte *)malloc( windowWidth * windowHeight * 4 );
	if( !imageBuffer ) {
		return false;
	}
	memset( imageBuffer, 0, windowWidth * windowHeight * 4 );

	TIFF *file = TIFFOpen(outFilename, "wb");
	if( file ) {
		glPixelStorei( GL_PACK_ALIGNMENT, 1 );
		glReadPixels( 0, 0, windowWidth, windowHeight, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer );

		TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) windowWidth);
		TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) windowHeight);
		TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8);
		TIFFSetField(file, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
		TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
		TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 4);
		TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
		TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1);
		TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, "");

		GLubyte *p = imageBuffer;
		for( int i = windowHeight - 1; i >= 0; i-- ) {
			if( TIFFWriteScanline(file, p, i, 0) < 0 ) {
				free(imageBuffer);
				TIFFClose(file);
				return false;
			}
		}
		p += windowWidth * sizeof(GLubyte) * 4 ;
	}
	TIFFClose(file);

	free( imageBuffer );
	return true;
}
void glutRenderingCallback() {
	glClearColor( 1.0f, 1.0f, 0.5f, 1.0f );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glLoadIdentity(); 

	glTranslatef( 0.0f, 0.0f, -5.0f );  
	glRotatef( 30.0f, 0.0f, 1.0f, 0.0f );
	glRotatef( 30.0f, 1.0f, 0.0f, 0.0f );
	glutSolidCube( 2.0f );

	glutSwapBuffers();

	if( takeSnapshot ) {
		glReadBuffer( GL_FRONT );
		snapshotTIFF( "test_front.tif" );
		glReadBuffer( GL_BACK );
		snapshotTIFF( "test_back.tif" );
		std::cout << "Took snapshot!" << std::endl;
		takeSnapshot = false;
	}
}

void glutReshapeCallback( int width, int height ) {  
	glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window  
	glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed  
	glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)  
	gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes  
	glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly  
}

void glutKeyboardCallback( unsigned char key, int x, int y ) {
	switch( key ) {
		case 's':
			takeSnapshot = true;
			break;
	}
}  

int main( int argc, char **argv ) {
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
	glutInitWindowSize( windowWidth, windowHeight );
	glutInitWindowPosition( 100, 100 );
	glutCreateWindow( "****** Simulation" );
	glEnable( GL_DEPTH_TEST );
	glEnable( GL_LIGHTING );
	glEnable( GL_LIGHT0 );
	glutDisplayFunc( glutRenderingCallback );
	glutIdleFunc( glutRenderingCallback );
	glutReshapeFunc( glutReshapeCallback );
	glutKeyboardFunc( glutKeyboardCallback );
	glutMainLoop();
	return 0;
}
Weiterhin bekomme ich nur die "Hintergrundfarbe" gespeichert. Dabei sollte doch der Framebuffer eine 1:1 Repräsentation dessen sein, was ich auch im Renderingfenster sehe, oder?

@joggel:
joggel hat geschrieben:Also, du könntest dann auch in deiner snapshotTIFF den Quellbuffer, aus dem die Pixel gelesen werden sollen, mittels glReadBuffer(GL_BACK) angeben, und dann ganz normal deine glReadPixels durchführen.
Japps, dachte ich auch. Deswegen lasse ich mir einmal den Front- und einmal den Backbuffer in separate Bilder schreiben. Leider sind beide "leer".

Viele Grüße,
Tim
Zuletzt geändert von Chromanoid am 11.07.2012, 23:04, insgesamt 1-mal geändert.
Grund: Kleiner Tipp von einem Moderator (-: [code=cpp] für Syntax-Highlighting
HalcyonDays
Beiträge: 4
Registriert: 10.07.2012, 15:58
Echter Name: Tim
Wohnort: Aachen

Re: Framebuffer in eine Datei sichern

Beitrag von HalcyonDays »

Hey,

also ich habe den Fehler "gefunden". Ich habe zum Test einfach mal eine andere Variante zur Erzeugung des Bildes gewählt:

Code: Alles auswählen

bool snapshotFreeImage( const char *outFilename ) {
        GLubyte *imageBuffer = (GLubyte *)malloc( windowWidth * windowHeight * 3 );
        if( !imageBuffer ) {
                return false;
        }
        memset( imageBuffer, 0, windowWidth * windowHeight * 3 );
        glPixelStorei( GL_PACK_ALIGNMENT, 1 );
        glReadPixels( 0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, imageBuffer );
        FIBITMAP* image = FreeImage_ConvertFromRawBits( imageBuffer, windowWidth, windowHeight, 3 * windowWidth, 24, 0x0000FF, 0xFF0000, 0x00FF00, false);
        FreeImage_Save(FIF_PNG, image, outFilename, 0);
        free( imageBuffer );
}
Plötzlich sehe ich auch den Würfel in dem Bild. Scheinbar mache ich irgendwo einen Fehler beim ansprechen der libTIFF Befehle :(

Viele Grüße,
Tim
Antworten