Replacing pBuffers with FBOs(glow effect)

Hi there
I’m currently reading an article about the glow effect from the book More OpenGL Game Programming.However I have no idea about the pBuffers. Unfortunately, this article has used pBuffers instead of FBOs.Unfortunately, asking a lot of questions is difficult.
I have many questions. Let’s start them step by step.
1)First of all he has initialized the pBuffers:

	// PBUFFERS INITIALIZATION
	for(int i=0; i<2; i++) if(! pbuffer[i]->Initialize(256, 256, true, false)) return false;

	// CREATE OUR RENDER TEXTURE OBJECT
    glGenTextures(1, &m_iRenderTexture);
	glBindTexture(GL_TEXTURE_2D, m_iRenderTexture);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//_MIPMAP_LINEAR);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	// notice that we don't need to call glTexImage2D for this texture object

Does it mean the he has attached the m_iRenderTexture texture to the pBuffers? Has he shared this texture among them?

As he has explained, he has used these steps to render the glow effect:
A) Render the scene as normal to the frame buffer
B) Render the same scene to a texture while disabling the lighting and shader.

After the B step, he has applied 2 shaders to the texture. the first one blurs the texture for 5 times. The second shader adds a few contrast to the texture. finally, he has used additive blending to add the texture color to the scene.

Here’s his code to render the glow effect:


void MGLApp::Render()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix(); glLoadIdentity();
	gluLookAt(10, 10, 10, 0,0,0, 0,1,0);
	SetupLighting();
	
	glRotatef( 20.f * (float)m_dElapTime, 0.f, 1.f, 0.f );
	glRotatef( -90, 0.1f, 0.0f, 0.0f);
	
	glEnable(GL_TEXTURE_2D);
	RenderGeometry();
	
	pbuffer[0]->Activate(); // make pbuffer[0] to be a render target
	glPushAttrib(GL_VIEWPORT_BIT | GL_POLYGON_BIT); 
		// set vieport to pbuffer's size
		glViewport( 0, 0, pbuffer[0]->GetWidth(), pbuffer[0]->GetHeight()); 
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
						
		glEnable(GL_TEXTURE_2D);
		glPushMatrix();
		// adding little scale to model. This will make effect to be more noticable
		glScalef(1.05f, 1.05f, 1.05f);
		// render geometry whithout lighting
		RenderGeometry(false);
		glPopMatrix();
	
		pbuffer[0]->SwapBuffers(); // this instruction makes pbuffer content available as a texture
		
	glPopAttrib();
	pbuffer[0]->Deactivate();
	
	// BLURRING SCREEN SPACE TEXTURE
	glUseProgramObjectARB(m_iBlurShader);
[color:#FF0000]	glBindTexture(GL_TEXTURE_2D, m_iRenderTexture);[/color]

	glMatrixMode(GL_MODELVIEW); glPushMatrix();	glLoadIdentity();
	glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
	glOrtho(0, 1, 0, 1, 0.01, 100);
	glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); 
	glViewport( 0, 0, pbuffer[0]->GetWidth(), pbuffer[0]->GetHeight());
	glDisable(GL_DEPTH_TEST); 
	
	int buff_index=0;
	

		for(int i=0; i<5; i++, buff_index=!buff_index)
		{
			pbuffer[buff_index]->Bind(WGL_FRONT_LEFT_ARB); // binding buffer to a texture
			pbuffer[!buff_index]->Activate();
		
			glBegin(GL_QUADS);
			glTexCoord2d(0,	0);	glVertex3d(0, 0, -1); 
			glTexCoord2d(1, 0);	glVertex3d(1, 0, -1);
			glTexCoord2d(1, 1);	glVertex3d(1, 1, -1);
			glTexCoord2d(0, 1);	glVertex3d(0, 1, -1);
			glEnd();

			pbuffer[buff_index]->Release(WGL_FRONT_LEFT_ARB);
			
			pbuffer[!buff_index]->SwapBuffers();
			pbuffer[!buff_index]->Deactivate();
		}
	glPopAttrib();
	glMatrixMode(GL_PROJECTION); glPopMatrix();
	glMatrixMode(GL_MODELVIEW); glPopMatrix();

	// RENDERING SCREEN SPACE TEXTURE TO FRAMEBUFFER

		glUseProgramObjectARB(m_iGlowShader);

		glBindTexture(GL_TEXTURE_2D, m_iRenderTexture);
		pbuffer[buff_index]->Bind(WGL_FRONT_LEFT_ARB);

		glMatrixMode(GL_MODELVIEW); glPushMatrix();	glLoadIdentity();
		glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
		glOrtho(0, 1, 0, 1, 0.01, 100);
		
		glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 
		glDisable(GL_DEPTH_TEST); 
		// additive blending setup
		glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE);
		
		glBegin(GL_QUADS);
		glTexCoord2d(0,	0);	glVertex3d(0, 0, -1); 
		glTexCoord2d(1, 0);	glVertex3d(1, 0, -1);
		glTexCoord2d(1, 1);	glVertex3d(1, 1, -1);
		glTexCoord2d(0, 1);	glVertex3d(0, 1, -1);
		glEnd();
		
		glPopAttrib();
		glMatrixMode(GL_PROJECTION); glPopMatrix();
		glMatrixMode(GL_MODELVIEW); glPopMatrix();

		pbuffer[buff_index]->Release(WGL_FRONT_LEFT_ARB); // release pbuffer texture for further rendering	
	

	glPopMatrix();
}

Here are my questions:
2)In the following code, does it mean that he has rendered to the m_iRenderTexture using a pBuffer?


	pbuffer[0]->Activate(); // make pbuffer[0] to be a render target
	glPushAttrib(GL_VIEWPORT_BIT | GL_POLYGON_BIT); 
		// set vieport to pbuffer's size
		glViewport( 0, 0, pbuffer[0]->GetWidth(), pbuffer[0]->GetHeight()); 
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
						
		glEnable(GL_TEXTURE_2D);
		glPushMatrix();
		// adding little scale to model. This will make effect to be more noticable
		glScalef(1.05f, 1.05f, 1.05f);
		// render geometry whithout lighting
		RenderGeometry(false);
		glPopMatrix();
	
		pbuffer[0]->SwapBuffers(); // this instruction makes pbuffer content available as a texture
		
	glPopAttrib();
	pbuffer[0]->Deactivate();
	

  1. Why he has bound the following texture while using the blur shader?
    glBindTexture(GL_TEXTURE_2D, m_iRenderTexture);
    ( I have specified it as red color in the code )

As you see he has used 2 pBuffers to blur the texture:


	int buff_index=0;
	

		for(int i=0; i<5; i++, buff_index=!buff_index)
		{
			pbuffer[buff_index]->Bind(WGL_FRONT_LEFT_ARB); // binding buffer to a texture
			pbuffer[!buff_index]->Activate();
		
			glBegin(GL_QUADS);
			glTexCoord2d(0,	0);	glVertex3d(0, 0, -1); 
			glTexCoord2d(1, 0);	glVertex3d(1, 0, -1);
			glTexCoord2d(1, 1);	glVertex3d(1, 1, -1);
			glTexCoord2d(0, 1);	glVertex3d(0, 1, -1);
			glEnd();

			pbuffer[buff_index]->Release(WGL_FRONT_LEFT_ARB);
			
			pbuffer[!buff_index]->SwapBuffers();
			pbuffer[!buff_index]->Deactivate();
		}
	glPopAttrib();
	glMatrixMode(GL_PROJECTION); glPopMatrix();
	glMatrixMode(GL_MODELVIEW); glPopMatrix();



  1. How can I replace this part of code with the FBOs?( How can I copy the contents of one FBO to another FBO? )

5)As you saw, to apply the glow shader and adding the glow effect, he has used the following code:


	// RENDERING SCREEN SPACE TEXTURE TO FRAMEBUFFER

		glUseProgramObjectARB(m_iGlowShader);

		glBindTexture(GL_TEXTURE_2D, m_iRenderTexture);
		pbuffer[buff_index]->Bind(WGL_FRONT_LEFT_ARB);

		glMatrixMode(GL_MODELVIEW); glPushMatrix();	glLoadIdentity();
		glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
		glOrtho(0, 1, 0, 1, 0.01, 100);
		
		glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 
		glDisable(GL_DEPTH_TEST); 
		// additive blending setup
		glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE);
		
		glBegin(GL_QUADS);
		glTexCoord2d(0,	0);	glVertex3d(0, 0, -1); 
		glTexCoord2d(1, 0);	glVertex3d(1, 0, -1);
		glTexCoord2d(1, 1);	glVertex3d(1, 1, -1);
		glTexCoord2d(0, 1);	glVertex3d(0, 1, -1);
		glEnd();
		
		glPopAttrib();
		glMatrixMode(GL_PROJECTION); glPopMatrix();
		glMatrixMode(GL_MODELVIEW); glPopMatrix();

		pbuffer[buff_index]->Release(WGL_FRONT_LEFT_ARB); // release pbuffer texture for further rendering	
	

	glPopMatrix();

  1. why he have bound the “pbuffer[buff_index]->Bind(WGL_FRONT_LEFT_ARB);” in this part of code?

Note: here are the blur and glow shaders:

blur shader:


[vertex]

uniform float radius_x, radius_y; // typycally radius_x = 1.0 / (texture resolution x)

void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0 - vec4(-radius_x, 0.0, 0.0, 0.0);
    gl_TexCoord[1] = gl_MultiTexCoord0 - vec4(radius_x, 0.0, 0.0, 0.0);
    gl_TexCoord[2] = gl_MultiTexCoord0 - vec4(0.0, -radius_y, 0.0, 0.0);
    gl_TexCoord[3] = gl_MultiTexCoord0 - vec4(0.0, radius_y, 0.0, 0.0);
    
    gl_Position = ftransform();
}



[fragment]
uniform sampler2D tex_unit_0; // texture from previous blurring stage

void main()
{
	vec4 sample[4];
	
	sample[0] = texture2D(tex_unit_0, gl_TexCoord[0].st);
	sample[1] = texture2D(tex_unit_0, gl_TexCoord[1].st);
	sample[2] = texture2D(tex_unit_0, gl_TexCoord[2].st);
	sample[3] = texture2D(tex_unit_0, gl_TexCoord[3].st);

	gl_FragColor = 	(sample[0] + sample[1] + sample[2] + sample[3]) / 4.0;
}

Glow shader:


[vertex]

void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
}



[fragment]
uniform sampler2D tex_unit_0; // blurred screen space texture

void main()
{
	vec3 sample = texture2D(tex_unit_0, gl_TexCoord[0].st).rgb;
	
	sample = (pow(sample, vec3(2.0))- vec3(0.0, 0.2, 0.2) )*3.0;
	
	gl_FragColor = 	vec4(sample, 1.0);
}


hi,
You first three questions are related to how we accompalish render to texture func. using PBOs when we had no FBOs.

For Q4, there are many ways, the simplest is to attach two color attachments to your FBO. Then, in your rendering code, use (assuming that your binding are to color attchmt 0 and 1)

GLenum colAttchs[2]={GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glBindFrameBuffer(GL_DRAWFRAMEBUFFER, fboID);
glDrawBuffers(2, colAttchs);
//do your rendering here

to direct rendering to the two attachments in a single pass. ANother option is to use glBlitFramebuffer func. http://www.opengl.org/sdk/docs/man3/xhtml/glBlitFramebuffer.xml

Q5 the reason for binding the front left buffer is to rebind the drawbiffer so that the rendering could continue on te display framebuffer, for your code u will use glDrawBuffer(GL_FRONT_LEFT);

Hope this helps,
Mobeen

Hi Mobeen
Thank you, but I didn’t understand your comments at all. specially, you didn’t response to my first 3 questions.It’s clear that the three questions are related to how we accompalish render to texture using PBOs when we had no FBOs!

OK, I thought u would get these let me discuss them.
Q1) Yes he is setting up an offscreen render target.
Q2) Yes he is rendering to the offscreen render target but is scaling the geometry slightly to make a more pronounced glow.
Q3) Since he is not setting the shader uniform, i think the texture binding is linking the render target to the shader. In your case u would set a shader uniform and pass the FBO attachment to it as texture map.

Hope this helps,
Mobeen

I could understand the first and second questions. but I didn’t understand the others. Can you give me an example or explain more about them?Sorry, but I have just used simple FBOs to render to textures.
And about question 3: do you mean that the texture is sent to gl_MultiTexCoord0 of the blur texture?

Assuming that I have 2 color buffers, how can I apply its textures to this code?
for example, here’s my FBO with 2 textures:


glGenTextures(1, &color_tex);
  glBindTexture(GL_TEXTURE_2D, color_tex);
  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_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  //NULL means reserve texture memory, but texels are undefined
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
  //-------------------------

glGenTextures(1, &color_tex2);
  glBindTexture(GL_TEXTURE_2D, color_tex2);
  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_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  //NULL means reserve texture memory, but texels are undefined
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
//----------------------------
  glGenFramebuffersEXT(1, &fb);
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
  //Attach 2D texture to this FBO
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0);

  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, color_tex2, 0);
  //-------------------------
  glGenRenderbuffersEXT(1, &depth_rb);
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb);
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256);
  //-------------------------
  //Attach depth buffer to FBO
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb);

( Is this code a correct way to create and attach 2 texture to the color buffers of the FBO? )

gl_MultiTexCoord0 is the texture coordinate for multitexturing. Since I have not seen the pbuffer class code, I suspect that the author is attaching the texture to the currently active texture unit 0 i.e. (GL_TEXTURE0 which is the default active texture unit) and referencing it in the shader. If I see the pbuffer class I cud tell u more about this.

Yes this looks ok.
Now for sending the texture to the blur and glow shader, you can send it as a shader uniform using something like this (assuming that you program is progID and the sampler name in the shader is textureMap),


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, color_tex);
glUniform1i(glGetUniformLocation(progID, "textureMap"), 0);
//0 is the texture unit where our texture is bound

Hope this helps,
Mobeen

Thanks
I uploaded the source code here:
http://www.speedyshare.com/files/25992399/Glow_Earth.rar
Please download glowEarth.rar.
Locate “void MGLApp::Render()” and you’ll see the rendering code. Actually, I have rendered the scene to the FBO, but I don’t understand how to use the FBO to render and blur the texture for N times. I have asked this question in the beginners forum. I’m new to post processing effects. So I need some extra information about processing the texture for N times.
someone has asked this question at gamedev.net:
http://www.gamedev.net/community/forums/topic.asp?topic_id=519459

I could finally implement the bloom effect with FBOs. Here are 3 screenshots: