Seite 1 von 1

Framebuffer in eine Datei sichern

Verfasst: 10.07.2012, 16:03
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

Re: Framebuffer in eine Datei sichern

Verfasst: 10.07.2012, 16:48
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?

Re: Framebuffer in eine Datei sichern

Verfasst: 10.07.2012, 21:01
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

Re: Framebuffer in eine Datei sichern

Verfasst: 10.07.2012, 22:24
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.

Re: Framebuffer in eine Datei sichern

Verfasst: 11.07.2012, 07:41
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...

Re: Framebuffer in eine Datei sichern

Verfasst: 11.07.2012, 07:47
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

Re: Framebuffer in eine Datei sichern

Verfasst: 11.07.2012, 08:49
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