help with blur/glow effect

Started by
3 comments, last by m-ray-y 15 years ago
Hi guys, i'm currently working on a solar system simulator but i'm having trouble with my glow effect for the sun, the effect works fine if the sun is the center of the scene, but if i move the camera to a different center, say one of the planets the glow effect is distorted, can anyone help? below are screenshots of what i meen and my code, thanks! sun at the center: sun center a planet at the center: Photobucket my code for generating and rendering the blur effect:

void ViewOrtho()							// Set Up An Ortho View
{
	glMatrixMode(GL_PROJECTION);					// Select Projection
	glPushMatrix();							// Push The Matrix
	glLoadIdentity();						// Reset The Matrix
	glOrtho( 0, winR , winT , 0, -1, 1 );				// Select Ortho Mode (640x480)
	glMatrixMode(GL_MODELVIEW);					// Select Modelview Matrix
	glPushMatrix();							// Push The Matrix
	glLoadIdentity();						// Reset The Matrix
}

void ViewPerspective()							// Set Up A Perspective View
{
	glMatrixMode( GL_PROJECTION );					// Select Projection
	glPopMatrix();							// Pop The Matrix
	glMatrixMode( GL_MODELVIEW );					// Select Modelview
	glPopMatrix();							// Pop The Matrix
}

void DrawBlur(int times, float inc)					// Draw The Blurred Image
{
	float spost = 0.0f;						// Starting Texture Coordinate Offset
	float alphainc = 0.9f / times;					// Fade Speed For Alpha Blending
	float alpha = 0.2f;						// Starting Alpha Value

	 //Disable AutoTexture Coordinates
	glDisable(GL_TEXTURE_GEN_S);
	glDisable(GL_TEXTURE_GEN_T);

	glEnable(GL_TEXTURE_2D);					// Enable 2D Texture Mapping
	glDisable(GL_DEPTH_TEST);					// Disable Depth Testing
	glBlendFunc(GL_SRC_ALPHA,GL_ONE);				// Set Blending Mode
	glEnable(GL_BLEND);						// Enable Blending
	glBindTexture(GL_TEXTURE_2D,BlurTexture);			// Bind To The Blur Texture
	ViewOrtho();							// Switch To An Ortho View

	alphainc = alpha / times;					// alphainc=0.2f / Times To Render Blur   

	glBegin(GL_QUADS);						// Begin Drawing Quads
		for (int num = 0;num < times;num++)			// Number Of Times To Render Blur
		{
			glColor4f(1.0f, 1.0f, 1.0f, alpha);		// Set The Alpha Value (Starts At 0.2)
			glTexCoord2f(0+spost,1-spost);			// Texture Coordinate	(   0,   1 )
			glVertex2f(0,0);				// First Vertex		(   0,   0 )

			glTexCoord2f(0+spost,0+spost);			// Texture Coordinate	(   0,   0 )
			glVertex2f(0,winT);				// Second Vertex	(   0, 480 )

			glTexCoord2f(1-spost,0+spost);			// Texture Coordinate	(   1,   0 )
			glVertex2f(winR,winT);				// Third Vertex		( 640, 480 )

			glTexCoord2f(1-spost,1-spost);			// Texture Coordinate	(   1,   1 )
			glVertex2f(winR,0);				// Fourth Vertex	( 640,   0 )

			spost += 0.01;					// Gradually Increase spost (Zooming Closer To Texture Center)
			alpha = alpha - alphainc;			// Gradually Decrease alpha (Gradually Fading Image Out)
		}
	glEnd();							// Done Drawing Quads

	ViewPerspective();						// Switch To A Perspective View

	glEnable(GL_DEPTH_TEST);					// Enable Depth Testing
	glDisable(GL_TEXTURE_2D);					// Disable 2D Texture Mapping
	//glDisable(GL_BLEND);						// Disable Blending
	glBindTexture(GL_TEXTURE_2D,0);					// Unbind The Blur Texture
}


void RenderToTexture()							// Renders To A Texture
{
	glViewport(0,0,600,600);
	glEnable(GL_TEXTURE_2D);   // Set Our Viewport (Match Texture Size)
	glBindTexture(GL_TEXTURE_2D,image[1]);
	star1.Draw();						// Render The Helix
	glBindTexture(GL_TEXTURE_2D,BlurTexture);			// Bind To The Blur Texture

	// Copy Our ViewPort To The Blur Texture (From 0,0 To 128,128... No Border)
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 600, 600, 0);

	glClearColor(0.0f, 0.0f, 0.0f, 0.5);				// Set The Clear Color To Medium Blue
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And Depth Buffer

	glViewport(0 , 0,winR ,winT);					// Set Viewport (0,0 to 640x480)
}


Advertisement
Admittedly I'm not very experienced with this, but I don't think what you're doing will work the way you want it to, unless what you're blurring is in the center of the screen - the way I visualize what your loop is doing is zooming in closer and closer on the blur texture while keeping the texture centered. This means that every iteration, everything 'moves' further away from the centre - including the points on the edge of your sun.

This will work as long as what you're blurring is in the centre of the screen, since the loop will produce larger and larger concentric circles around the centre. However, if something isn't in the centre to start with, every iteration will make it a bit bigger, but also move it towards the screen edge.

If that doesn't make much sense, imagine what happens to a point on the edge of your sun with every iteration - it gets slightly bigger, but since we already established that the edge of the sun is growing, the location of the point would also be moving away from the centre of the screen (since it'd still be on the edge).

I don't know if this is the problem, but it sort-of makes sense in my head.

Since you're already rendering to a texture, I'd actually recommend a simple gaussian blur fragment shader instead, if using shaders is an option.
what you're saying seems to make sense, and if you're correct then i'd like to implement a shader tough i've no experience with them, how would i go about implementing one to create my desired effect? unless anyone has else has any suggestions about how to slove my problem?
Regarding shaders, I found the lighthouse3d tutorials very helpful. I'll add my shader loading function to this post to help get you started - note that it uses OpenGL 2.0 syntax, which may or may not work on your machine. If it doesn't, you'll want to use the ARB syntax. The lighthouse3d article explains the differences - in practice it involves adding "ARB" to the end of most function names. When the shaders are compiled and loaded, you get an identifier to your vertex+fragment shader combination (called a "program"), and you can bind and unbind it, sort-of like textures.

So, you'd do all the stuff in the loading function, and then
glUseProgram(someProgram);//draw stuff using shaders hereglUseProgram(0);//draw stuff without shaders here


As for the blur effect, here is a Gamasutra article about glow effects and gaussian blur in particular. The code is all Direct3D, but the article gives a good high-level overview. You're going to want a simple pass-through vertex shader (which simply does what OpenGL would do normally to your vertices), and either a one-pass or two-pass fragment shader.

A one-pass shader would be used as such:
* Render the scene to a glow texture (probably one where whatever you want to glow is colored, and the rest is black, but this can be done using alpha etc.);
* Enable the shader;
* Render the texture to a target texture, having your shader do the magic as it gets there;
* Disable the shader;
* Render the scene normally;
* Enable additive blending, and render the blur target texture on a full-screen quad.

You can use framebuffers instead of textures, but this should be easier to start with :)

A very simple shader could work as such:
* For every pixel:
* Check the color value of the pixel to the left, multiply by a value F, add to someValue
* Check the color value of the pixel to the right, multiply by a value F, add to someValue
* Check the color value of the pixel above, multiply by a value F, add to someValue
* Check the color value of the pixel below, multiply by a value F, add to someValue
* Divide someValue by F*4
* Add someValue to the color value of the current pixel

You can do this in two passes, horizontally and then vertically, but the Gamasutra discusses this in detail.

Here's my shader loader, along with a simple text file reading function, in C. They're probably both pretty ugly, but they've worked for me so far :)
char *readFile(const char *filename);GLint initShader(const char * vertexShaderName, const char * fragmentShaderName);char *readFile(const char *fn) {	FILE *fp;	char *content = NULL;	long count=0;	if (fn != NULL) {		fp = fopen(fn,"r");		if (fp != NULL) {			fseek(fp, 0, SEEK_END);			count = ftell(fp);			rewind(fp);			if (count > 0) {				content = (char *)malloc(sizeof(char) * (count+1));				count = fread(content,sizeof(char),count,fp);				content[count] = '\0';			}			fclose(fp);		}	}	return content;}GLint initShader(const char * vertexShaderName, const char * fragmentShaderName) {	GLchar log[1024] = {};	GLsizei logLength = 0;	GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER);	GLuint vshader = glCreateShader(GL_VERTEX_SHADER);	GLuint program = 0;	char * fsource = readFile(fragmentShaderName);	char * vsource = readFile(vertexShaderName);	const char * fsourceptr = fsource;	const char * vsourceptr = vsource;	glShaderSource(fshader, 1, &fsourceptr, NULL);	glShaderSource(vshader, 1, &vsourceptr, NULL);	free(fsource);	free(vsource);	glCompileShader(fshader);	glCompileShader(vshader);	glGetShaderInfoLog(fshader, 1024, &logLength, log);	if (logLength)		printf("fshader \"%s\" log: %s\n", fragmentShaderName, log);	else		printf("fshader \"%s\" compiled OK.\n", fragmentShaderName);	logLength = 0;	glGetShaderInfoLog(vshader, 1024, &logLength, log);	if (logLength)		printf("vshader \"%s\" log: %s\n", vertexShaderName, log);	else		printf("vshader \"%s\" compiled OK.\n", vertexShaderName);	logLength = 0;	program = glCreateProgram();	glAttachShader(program, fshader);	glAttachShader(program, vshader);	glLinkProgram(program);	glGetProgramInfoLog(program, 1024, &logLength, log);	if (logLength)		printf("Program log: %s\n", log);	else		printf("Shader program %lu\n  f:\"%s\"\n  v:\"%s\"\nattached and linked OK.\n", program, fragmentShaderName, vertexShaderName);	logLength = 0;		return program;}


There's a few good tutorials specifically about GLSL glow shaders on the internet, I'll see if I can find a couple links that got me started. Have fun!
as "peachu" said , using shaders is the best
to create blur , just do simple guassain
but to create Glow for some objects, you would have to render those objects on the render target
then in other pass (post screen effect ) you make the blur effect on the rendered pixels of that object

hint : to minimize the complexity of blurring the image , you can lower the resultion of the texture after rendering on it , then combine it with the old render target using shader

This topic is closed to new replies.

Advertisement