Render Normals to Texture G-Buffer (for deferred shading) FBO MRT [MRT SOLVED]

Started by
7 comments, last by zaneski13 14 years, 2 months ago
Hi, I've been looking into deferred lighting and looks quite interesting. I saw that the Leadwerks engine uses it and their screen shots look great. I just haven't been able to find out a process in the deferred lighting algorithm. It involves the G-Buffer. IE: the Geometry Buffer. It has to store a texture containing all of the normals and all of the depth values. (Z buffer) I'm more curious about the normal rendering texture. Like, how do I generate it? And also, how do I get the depth buffer as a texture? Thanks. [Edited by - zaneski13 on February 15, 2010 10:28:59 PM]
Advertisement
What's the problem you're having? You draw normals like you draw anything else - output the data you want to store in the texture as color from your fragment shader

Most people use MRT for their G-Buffer pass so they can output at least normals, albedo, and some material specular values

Getting the depth buffer as a texture depends on the graphics api you're using. Check the documentation, it'll tell you.
" What's the problem you're having? You draw normals like you draw anything else - output the data you want to store in the texture as color from your fragment shader"

Thanks, I couldn't understand how people got those random looking textures...

Ok, so each pixel is a normal.xyz value but how exactly do I get that data? I'm only storing the normals for every face in my scene, not every pixel, so how do I generate that texture? I'm not sure how I'm supposed to go from storing faces with normals in 3D space to normals as pixels in 2D space.
Well, your vertex buffer will have to have a normal per vertex (much like it already has a position per vertex, and maybe UVs if you've got textures working). You'll send this data into your vertex shader where you'll transform it to (typically) world space or view space, and output it to the fragment shader. In the fragment shader you'll want to normalize the normal and output it to your normal buffer.
So you output that information into the normal buffer? Is that something defined in opengl already where I can get data from or do I have to create it? And then, how do shaders store stuff in a buffer so that the main program can access it? Or the other way around, how does the shader output data into a texture where in the main program I can retrieve? Is there a good source or tutorial that I could follow because the ones I found didn't explain much, just the theory behind it all.
Tell me if I'm right,
I draw the scene once and make the color of the drawn face's its normal.xyz. When done rendering grab the framebuffer and send it to a texture. Using glReadPixel(). Now you have the normal texture. You then clear the screen and draw the scene based on depth, so the color would be pos.zzz (red = z, green = z, blue = z). You then get the framebuffer and send hat to a texture using glReadPixel(). and do the same thing for specular factor and albedo. (whatever albedo is...?) With those textures you can pass them to a shader and do calculations which modify pixels on the screen based on light positions. Something tells me that I'm not doing this right because that would require me to draw the scene 4 times to generate the 4 textures I need.
Draw the scene once, and use MRT (multiple-render-targets) to output all of the attributes to N render targets (where N might be 3 or 4 or however many you need).
AHA! thanks, I found a really nice source to help explain MRT and FBO's
I had no idea about gl_FragData[] in glsl. Its exactly what I needed. Now I just need to implement it... I'll come back if I have any problems or questions. Thanks again!

source is here in case anyone wants to read it
http://www.gamedev.net/reference/articles/article2333.asp
I implemented MRT today. It took me FOREVER to do it though because I couldn't find much source code. So I'll just post mine so if any of you noobs need a reference.


First my Shader.h file
#ifndef SHADER_H#define SHADER_H#include <GL/glew.h>#include <string>#include <fstream>using std::string;class Shader{public:	Shader( string vertexFile, string fragFile );	void useShader(void);	static void disableShader(void);	void setAttribute1i( string name, int x );	void setAttribute2i( string name, int x, int y );	void setAttribute3i( string name, int x, int y, int z );	void setAttribute4i( string name, int x, int y, int z, int w );	void setAttribute1f( string name, float x );	void setAttribute2f( string name, float x, float y );	void setAttribute3f( string name, float x, float y, float z );	void setAttribute4f( string name, float x, float y, float z, float w );	void setAttributeMat4( string name, float mat4[16] );private:	char * readFile(const char *fn);private:	GLhandleARB vertexShader;	GLhandleARB fragmentShader;	GLhandleARB program;};#endif



Now my Shader.cpp file

#include "shader.h"Shader::Shader( string vertexFile, string fragFile ){	vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);	fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);		const char *vv = readFile(vertexFile.data());		const char *ff = readFile(fragFile.data());		if ( vv != NULL && ff != NULL )		{			glShaderSourceARB( vertexShader, 1, &vv, NULL );			glShaderSourceARB( fragmentShader, 1, &ff, NULL );			delete [] vv;			delete [] ff;			glCompileShaderARB(vertexShader);			glCompileShaderARB(fragmentShader);			program = glCreateProgramObjectARB();			glAttachObjectARB(program, vertexShader); //attach shader into program			glAttachObjectARB(program, fragmentShader);			glLinkProgramARB(program);		}}void Shader::useShader(void){	glUseProgramObjectARB(program);}void Shader::disableShader(void){	glUseProgramObjectARB(NULL);}void Shader::setAttribute1i( string name, int x ){	glUniform1iARB( glGetUniformLocationARB(program, name.data()), x );}void Shader::setAttribute2i( string name, int x, int y ){	glUniform2iARB( glGetUniformLocationARB(program, name.data()), x, y );}void Shader::setAttribute3i( string name, int x, int y, int z ){	glUniform3iARB( glGetUniformLocationARB(program, name.data()), x, y, z );}void Shader::setAttribute4i( string name, int x, int y, int z, int w ){	glUniform4iARB( glGetUniformLocationARB(program, name.data()), x, y, z, w );}void Shader::setAttribute1f( string name, float x ){	glUniform1fARB( glGetUniformLocationARB(program, name.data()), x );}void Shader::setAttribute2f( string name, float x, float y ){	glUniform2fARB( glGetUniformLocationARB(program, name.data()), x, y );}void Shader::setAttribute3f( string name, float x, float y, float z ){	glUniform3fARB( glGetUniformLocationARB(program, name.data()), x, y, z );}void Shader::setAttribute4f( string name, float x, float y, float z, float w ){	glUniform4fARB( glGetUniformLocationARB(program, name.data()), x, y, z, w );}void Shader::setAttributeMat4( string name, float mat4[16] ){	glUniformMatrix4fvARB( glGetUniformLocationARB(program, name.data()), 16, false, mat4 );}char * Shader::readFile(const char *fn){	int length;	char *buffer;	std::ifstream file;	file.open(fn, std::ios::binary);	if ( file.is_open() == false )		return NULL;	file.seekg(0, std::ios::end);	length = file.tellg();	file.seekg(0, std::ios::beg);	buffer = new char[length];	file.read( buffer, length );	file.close();	return buffer;}


Now my main.cpp file

#include <windows.h>#include "SDL.h"#include "shader.h" //glew.h#include <GL/gl.h>#include <GL/glu.h>#include "glext.h"#include <iostream>using namespace std;//you don't need this because "glew.h" defines all this. THANKS GLEW!/*extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL;extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL;extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL;extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;*/const int screenWidth = 800;const int screenHeight = 600;GLuint fbo;GLuint renderBuffer;GLuint texture1;GLuint texture2;GLuint textureWidth = 1024;GLuint textureHeight = 1024;SDL_Event event;bool quit = false;float rotx = 0;float roty = 45;Shader *colorShader = NULL;void DrawCube(void); //define the func to use itbool InitEXT(void){	char *ext = (char*)glGetString( GL_EXTENSIONS );	if( strstr( ext, "EXT_framebuffer_object" ) == NULL )	{		MessageBox(NULL,"EXT_framebuffer_object extension was not found",			"ERROR",MB_OK|MB_ICONEXCLAMATION);		return false;	}	else	{		glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)wglGetProcAddress("glIsRenderbufferEXT");		glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");		glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)wglGetProcAddress("glDeleteRenderbuffersEXT");		glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)wglGetProcAddress("glGenRenderbuffersEXT");		glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)wglGetProcAddress("glRenderbufferStorageEXT");		glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)wglGetProcAddress("glGetRenderbufferParameterivEXT");		glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)wglGetProcAddress("glIsFramebufferEXT");		glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");		glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)wglGetProcAddress("glDeleteFramebuffersEXT");		glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)wglGetProcAddress("glGenFramebuffersEXT");		glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");		glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)wglGetProcAddress("glFramebufferTexture1DEXT");		glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddress("glFramebufferTexture2DEXT");		glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)wglGetProcAddress("glFramebufferTexture3DEXT");		glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)wglGetProcAddress("glFramebufferRenderbufferEXT");		glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)wglGetProcAddress("glGetFramebufferAttachmentParameterivEXT");		glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)wglGetProcAddress("glGenerateMipmapEXT");		if( !glIsRenderbufferEXT || !glBindRenderbufferEXT || !glDeleteRenderbuffersEXT || 			!glGenRenderbuffersEXT || !glRenderbufferStorageEXT || !glGetRenderbufferParameterivEXT || 			!glIsFramebufferEXT || !glBindFramebufferEXT || !glDeleteFramebuffersEXT || 			!glGenFramebuffersEXT || !glCheckFramebufferStatusEXT || !glFramebufferTexture1DEXT || 			!glFramebufferTexture2DEXT || !glFramebufferTexture3DEXT || !glFramebufferRenderbufferEXT||  			!glGetFramebufferAttachmentParameterivEXT || !glGenerateMipmapEXT )		{			MessageBox(NULL,"One or more EXT_framebuffer_object functions were not found",				"ERROR",MB_OK|MB_ICONEXCLAMATION);			return false;		}	}	return true;}bool CheckFramebufferStatus(void){	GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );	switch( status )	{		case GL_FRAMEBUFFER_COMPLETE_EXT:			//MessageBox(NULL,"GL_FRAMEBUFFER_COMPLETE_EXT!","SUCCESS",MB_OK|MB_ICONEXCLAMATION);			break;		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:			MessageBox(NULL,"GL_FRAMEBUFFER_UNSUPPORTED_EXT!","ERROR",MB_OK|MB_ICONEXCLAMATION);			return false;			break;		default:			return false;		}	return true;}int main(int argc, char **argv){	if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 )		return 0;	if ( SDL_SetVideoMode( screenWidth, screenHeight, 32, SDL_OPENGL | SDL_GL_DOUBLEBUFFER ) == NULL )		return 0;	glewInit();	glShadeModel( GL_SMOOTH );	glClearDepth( 1.0f );	glEnable( GL_DEPTH_TEST );	glDepthFunc( GL_LEQUAL );	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );	glEnable( GL_PERSPECTIVE_CORRECTION_HINT );	glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );	glEnable(GL_TEXTURE_2D);	if ( !InitEXT() )	{		SDL_Quit();		return 0;	}	//init shaders	if ( GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader ) //if shaders work	{		//setup shaders		colorShader = new Shader("shader.vert", "shader.frag");		colorShader->disableShader();	}	else	{		SDL_Quit();		return 0;	}	glGenFramebuffersEXT(1, &fbo); //generate the FBO	glGenRenderbuffersEXT(1, &renderBuffer); //generate the render buffer	glGenTextures(1, &texture1); //generate the texture, which we'll bind to the fbo to render to	glGenTextures(1, &texture2);	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); //binds the framebuffer	//initialize the renderBuffer	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuffer);	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, textureWidth, textureHeight); //create storage memory	//attach the renderBuffer to the currently bound framebuffer so it can store depth	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, renderBuffer );	//init the first texture we'll be rendering to	glBindTexture(GL_TEXTURE_2D, texture1);	//THE INTERNAL FORMAT IS GL_RGBA8 WHILE THE FORMAT GL_RGBA     NO 8!!!	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );	//init the second texture we'll be rendering to	glBindTexture(GL_TEXTURE_2D, texture2);	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	//attach the texture to the framebuffer so the frame buffer knows where to render to	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture1, NULL);	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, texture2, NULL);	if ( !CheckFramebufferStatus() )	{		quit = true;		cout << "fbo wasn't correctly bound to the render buffer" << endl; //gets here		system("Pause");	}	//yay, we're set up	while ( !quit )	{		while( SDL_PollEvent(&event) )		{			if ( event.type == SDL_QUIT )				quit = true;			if ( event.type == SDL_KEYDOWN )			{				if ( event.key.keysym.sym == SDLK_ESCAPE )					quit = true;			}		}		rotx += 0.05f;		roty += 0.03f;		//----------------------------		//----------------------------		//render		//----------------------------		//----------------------------		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo );		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuffer );		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture1, 0 );		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, texture2, 0);		glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, renderBuffer );		GLenum mrt[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };		glDrawBuffers(2, mrt);		glViewport( 0, 0, textureWidth, textureHeight );		glClearColor( 0.5f, 0.5f, 0.0f, 1.0f );		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );		//set projection matrix		glMatrixMode( GL_PROJECTION );		glLoadIdentity();		gluPerspective( 45, (GLsizei)screenWidth / (GLsizei)screenHeight, 0.05, 9900 );		glMatrixMode(GL_MODELVIEW);		glTranslatef(0.0f, 0.0f, -5.0f);		glRotatef(rotx, 1.0f, 0.0f, 0.0f );		glRotatef(roty, 0.0f, 1.0f, 0.0f );		//glColor3f(1.0f, 0.0f, 0.0f); //draw red cube		colorShader->useShader();		DrawCube();		colorShader->disableShader();		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, NULL); //disable writing to texture		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, NULL);		//---------------------------		//RENDER NORMALLY NOW!		//---------------------------		glViewport( 0, 0, screenWidth, screenHeight );		glClearColor( 0.7f, 0.7f, 0.7f, 1.0f );		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );		glMatrixMode(GL_MODELVIEW);		glLoadIdentity();		glTranslatef(0.0f, 0.0f, -5.0f);		glColor3f(1.0f, 1.0f, 1.0f);		glEnable(GL_TEXTURE_2D);		glBindTexture(GL_TEXTURE_2D, texture1); //bind the texture that the fbo wrote to		//blue texture		glBegin(GL_QUADS);		glTexCoord2f(0.0f, 0.0f);		glVertex3f(-2.1f,  1.0f, 0.0f);		glTexCoord2f(0.0f, 1.0f);		glVertex3f(-2.1f, -1.0f, 0.0f);		glTexCoord2f(1.0f, 1.0f);		glVertex3f(-0.1f, -1.0f, 0.0f);		glTexCoord2f(1.0f, 0.0f);		glVertex3f(-0.1f,  1.0f, 0.0f);		glEnd();		//red texture		glBindTexture(GL_TEXTURE_2D, texture2); //bind the texture that the fbo wrote to		glBegin(GL_QUADS);		glTexCoord2f(0.0f, 0.0f);		glVertex3f( 0.1f,  1.0f, 0.0f);		glTexCoord2f(0.0f, 1.0f);		glVertex3f( 0.1f, -1.0f, 0.0f);		glTexCoord2f(1.0f, 1.0f);		glVertex3f( 2.1f, -1.0f, 0.0f);		glTexCoord2f(1.0f, 0.0f);		glVertex3f( 2.1f,  1.0f, 0.0f);		glEnd();		glFlush();		SDL_GL_SwapBuffers();	}	if ( colorShader != NULL )	{		delete colorShader;		colorShader = NULL;	}	glDeleteFramebuffersEXT(1, &fbo);	glDeleteRenderbuffersEXT(1, &renderBuffer);	glDeleteTextures(1, &texture1);	glDeleteTextures(1, &texture2);	SDL_Quit();	return 1;}void DrawCube(void){	//draw the cube	glBegin(GL_QUADS);		//top face		glVertex3f(1.0f, 1.0f, -1.0f);		glVertex3f(-1.0f, 1.0f, -1.0f);		glColor3f(0.7f, 0.1f, 0.2f);		glVertex3f(-1.0f, 1.0f, 1.0f);		glVertex3f(1.0f, 1.0f, 1.0f);		//bottom face		glVertex3f(1.0f, -1.0f, -1.0f);		glColor3f(0.0f, 0.1f, 0.0f);		glVertex3f(-1.0f, -1.0f, -1.0f);		glColor3f(0.0f, 0.8f, 0.2f);		glVertex3f(-1.0f, -1.0f, 1.0f);		glColor3f(0.9f, 0.0f, 1.2f);		glVertex3f(1.0f, -1.0f, 1.0f);		//front face		glVertex3f( 1.0f,  1.0f,  1.0f);		glColor3f(0.0f, 0.9f, 0.8f);		glVertex3f(-1.0f,  1.0f,  1.0f);		glColor3f(1.0f, 0.7f, 0.2f);		glVertex3f(-1.0f, -1.0f,  1.0f);		glVertex3f( 1.0f, -1.0f,  1.0f);		//back face		glVertex3f( 1.0f,  1.0f, -1.0f);		glColor3f(0.2f, 0.8f, 0.5f);		glVertex3f(-1.0f,  1.0f, -1.0f);		glColor3f(0.6f, 0.1f, 0.2f);		glVertex3f(-1.0f, -1.0f, -1.0f);		glColor3f(0.0f, 0.0f, 0.3f);		glVertex3f( 1.0f, -1.0f, -1.0f);		//left face		glVertex3f(-1.0f, 1.0f, 1.0f);		glColor3f(0.35f, 0.18f, 0.4f);		glVertex3f(-1.0f, 1.0f, -1.0f);		glColor3f(1.0f, 0.55f, 0.25f);		glVertex3f(-1.0f,-1.0f, -1.0f);		glColor3f(0.0f, 0.0f, 0.15f);		glVertex3f(-1.0f,-1.0f, 1.0f);		//right face		glVertex3f(1.0f, 1.0f, 1.0f);		glColor3f(0.5f, 0.1f, 0.6f);		glVertex3f(1.0f, 1.0f, -1.0f);		glColor3f(0.6f, 0.0f, 0.2f);		glVertex3f(1.0f,-1.0f, -1.0f);		glColor3f(1.0f, 0.6f, 0.0f);		glVertex3f(1.0f,-1.0f, 1.0f);	glEnd();}


And now my shaders

//VERTvoid main(void){   gl_Position = ftransform();}//FRAGvoid main(void){   //we write the color blue to the cube bound to GL_COLOR_ATTACHMENT0_EXT   gl_FragData[0] = vec4( 0.0, 0.0, 1.0, 1.0 );   //we write the color red to the cube bound to GL_COLOR_ATTACHMENT1_EXT   gl_FragData[1] = vec4( 1.0, 0.0, 0.0, 1.0 );}


So hopefully this will help someone out there. :)

Also, some good sources I found were
http://www.gamedev.net/reference/articles/article2331.asp
http://www.gamedev.net/reference/articles/article2333.asp
http://www.idevgames.com/forum/showthread.php?t=15770 //didn't find this one until later :(
http://www.cs.kent.edu/~zhao/gpu/lectures/OpenGL_FrameBuffer_Object.pdf //This one really helped me

This topic is closed to new replies.

Advertisement