Jump to content
  • Advertisement
Sign in to follow this  
dc443

OpenGL [SDL-OpenGL-GLSL] Accessing frame buffer for use in fragment shader

This topic is 3713 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to make some pixel shader effects which require access to the frame buffer (e.g. visual distortion effects -- shockwaves, heat haze etc). My game is in 2D so I have no need for a depth buffer. I am trying to copy the framebuffer to a texture (for access through the shader) without success. I have followed the OpenGL Frame Buffer Object 101 tutorial on this site, which was very clear about everything, but it still does not work. I either get a white quad, or complete blackness. I feel that I may be missing something trivial. This is my shader testing code that I am trying to get to work (I will integrate it with my game after I get it working):
int main(int argc, char **argv)
{
	SDL_Event sdlEv;
	Uint32 sdlVideoFlags = SDL_OPENGL;
	Uint8 quit;
	char *extensions;
 
	int i, j;
 
	/* Initialize */
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
		exit(EXIT_FAILURE);
	}
	atexit(SDL_Quit);
 
	/* Start graphic system with OGL */
	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
 
	if (!SDL_SetVideoMode(512, 512, 0, sdlVideoFlags))
	{
		fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
		return EXIT_FAILURE;
	}
 
	glShadeModel(GL_SMOOTH);
	glViewport(0, 0, 512, 512);
 
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(40, 1, 0.0001, 1000.0);
	glMatrixMode(GL_MODELVIEW);
 
	printf("Initializing glew\n");
	glewInit();
	if (GLEW_VERSION_2_0)
		fprintf(stderr, "INFO: OpenGL 2.0 supported, proceeding\n");
	else
	{
		fprintf(stderr, "INFO: OpenGL 2.0 not supported. Exit\n");
		return EXIT_FAILURE;
	}
 
	/* The vertex shader */
	char *vsSource = file2string("wavey.vert");
	char *fsSource = file2string("wavey.frag");
 
	/* Compile and load the program */
 
	GLuint vs, /* Vertex Shader */
		   fs, /* Fragment Shader */
		   sp; /* Shader Program */

	int windowWidth = 512;
	int windowHeight = 512;
	


	
	
	GLuint fbo;
	glGenFramebuffersEXT(1, &fbo);

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

	GLuint img;
	glGenTextures(1, &img);
	glBindTexture(GL_TEXTURE_2D, img);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glGenerateMipmapEXT(GL_TEXTURE_2D);


	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, img, 0);

	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	if (status == GL_FRAMEBUFFER_COMPLETE_EXT)
		printf("good\n");


	


 
	vs = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vs, 1, (const GLchar**)&vsSource, NULL);
	glCompileShader(vs);
	printLog(vs);
 
	fs = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fs, 1, (const GLchar**)&fsSource, NULL);
	glCompileShader(fs);
	printLog(fs);
 
	free(vsSource);
	free(fsSource);
 
	sp = glCreateProgram();
	glAttachShader(sp, vs);
	glAttachShader(sp, fs);
	glLinkProgram(sp);
	printLog(sp);
 
	glUseProgram(sp);
 
	GLfloat waveTime = 0.0,
			waveWidth = 0.1,
			waveHeight = 3.0,
			waveFreq = 0.1;
	GLint waveTimeLoc = glGetUniformLocation(sp, "waveTime");
	GLint waveWidthLoc = glGetUniformLocation(sp, "waveWidth");
	GLint waveHeightLoc = glGetUniformLocation(sp, "waveHeight");
	GLint bufferTexLoc = glGetUniformLocation(sp, "framebuf");
	printLog(sp);
 
	printf("wave parameters location: %d %d %d\n", waveTimeLoc, waveWidthLoc, waveHeightLoc);
 
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

 
	int frameCount = 0;
	int nextUpdate = SDL_GetTicks() + 1000;
	/* Main loop */
	quit = 0;
	while (!quit)
	{
		while (SDL_PollEvent(&sdlEv))
			switch (sdlEv.type)
			{
				case SDL_QUIT:
					quit = 1;
					break;
 
				case SDL_KEYDOWN:
					switch (sdlEv.key.keysym.sym)
					{
						case SDLK_PLUS:
							waveFreq += 0.1;
							printf("Modified time waveFreq + 0.1: %f\n", waveFreq);
							break;
 
						case SDLK_MINUS:
							waveFreq -= 0.1;
							printf("Modified time waveFreq - 0.1: %f\n", waveFreq);
							break;
 
						case SDLK_w:
							waveWidth += 0.1;
							printf("Modified width waveWidth + 0.1: %f\n", waveWidth);
							break;
 
						case SDLK_q:
							waveWidth -= 0.1;
							printf("Modified width waveWidth - 0.1: %f\n", waveWidth);
							break;
 
						case SDLK_h:
							waveHeight += 0.1;
							printf("Modified width waveWidth + 0.1: %f\n", waveHeight);
							break;
 
						case SDLK_g:
							waveHeight -= 0.1;
							printf("Modified width waveWidth - 0.1: %f\n", waveHeight);
							break;
 
						default:
							break;
					}
 
				default:
					break;
			}
		
		glClear(GL_COLOR_BUFFER_BIT);
		glLoadIdentity();
 

		glColor3f(1,1,1);
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
		glPushAttrib(GL_VIEWPORT_BIT);
		glViewport(0,0,512, 512);

		//glPushMatrix();

		// Render as normal here

		glTranslatef(0.0, 0.0, -150.0);
		glRotatef(-45.0 + waveTime*5., 1.0, 0.0, 0.0);
 
		
		//glColor3f(0,0,0);
		/* Draw here a plain surface */
		glBegin(GL_QUADS);
		
		for (i = -50; i < 50; i+=2)
		{
			for (j = -50; j < 50; j+=2)
			{
				for(int k = 0; k < 1; k++)
				{
					glVertex3f(i, j, k);
					glVertex3f(i + 1, j, k+1);
					glVertex3f(i + 1, j + 1, k+1);
					glVertex3f(i, j + 1, k);
				}
			}
		}
	
		glEnd();
		//glPopMatrix();
		// output goes to the FBO and it’s attached buffers

		glPopAttrib();
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);




		//glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,512,512);

		//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		float x = 5;
		float y = 5;
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, img);
		glBegin(GL_QUADS);
		glTexCoord2f(0.0f,0.0f);
		glVertex2f(-x,-y);
		glTexCoord2f(1.0f,0.0f);
		glVertex2f(x,-y);
		glTexCoord2f(1.0f,1.0f);
		glVertex2f(x,y);
		glTexCoord2f(0.0f,1.0f);
		glVertex2f(-x,y);
		glEnd();
		glDisable(GL_TEXTURE_2D);


		/* Change time */
		glUniform1f(waveTimeLoc, waveTime);
		glUniform1f(waveWidthLoc, waveWidth);
		glUniform1f(waveHeightLoc, waveHeight);
		glUniform1i(bufferTexLoc, img);
 
		waveTime += waveFreq;
 
		
		SDL_GL_SwapBuffers();
		SDL_Delay(16);
		frameCount++;
 
		if (SDL_GetTicks() >= nextUpdate)
		{
			fprintf(stderr, "FPS: %d\n", frameCount);
			frameCount = 0;
			nextUpdate = SDL_GetTicks() + 1000;
		}
	}
 
	glDeleteShader(vs);
	glDeleteShader(fs);
	glDeleteProgram(sp);
 
	return EXIT_SUCCESS;
}

Share this post


Link to post
Share on other sites
Advertisement
Ah, I think I found a part of the problem. I didn't create routines to apply the texture coordinates in my fragment/ vertex shaders.

Still, I switched off the shaders and it renders nothing.

In any case, I seem to have gotten this working using this bit of code in my main program:


if (fbuffer == 0)
{
glGenTextures(1, &fbuffer);
glBindTexture(GL_TEXTURE_2D, fbuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Copies the contents of the frame buffer into the texture
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, power_of_two(Screen_Width), power_of_two(Screen_Height), 0);
} else {
// Copies the contents of the frame buffer into the texture
glBindTexture(GL_TEXTURE_2D, fbuffer);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, power_of_two(Screen_Width), power_of_two(Screen_Height));
}

Share this post


Link to post
Share on other sites
Quote:
Original post by agi_shi
Why not simply render the scene to a texture to begin with?


This was exactly what I was attempting to accomplish. It definitely seemed like it should be simple enough. Turns out it was, but my shader program's setup just didn't work with it.

I've got it working now, in my non-shader program.

Question: in order for me to use textures in a program that uses shaders, I must create vertex and fragment shaders which handle textures?

Share this post


Link to post
Share on other sites
Quote:
Original post by dc443
Question: in order for me to use textures in a program that uses shaders, I must create vertex and fragment shaders which handle textures?


Yup. Once you jump from fixed function -> shaders, you must handle everything yourself - fog, textures, lighting, all the Good Stuff :).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!