Jump to content
  • Advertisement
Sign in to follow this  
Solid_Spy

OpenGL Rendering Gui Or Hud In A Separate Framebuffer

This topic is 864 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

Hello, I have been trying to render the HUD for my game to a separate FrameBuffer so that I can apply my own shader effects to it that are separated from the 3D scene. So far it works fine with entirely opaque objects.

 

The problem is that I am having transparency issues. I use glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); with glClearColor(0.0f, 0.0f, 0.0f, 0.0f);, which creates a transparent black background for the HUD FrameBuffer before rendering the HUD.

 

Whenever I render a transparent HUD element to the FrameBuffer, the black gets mixed in with the original colors of the element, which is not what I want. It ends up making the HUD elements look darker than they are supposed to be.

 

I can change the color for glClearColor() and get different colored results, so I know that that is the root of the problem. I decided to use the blend function:

 

glBlendFuncSeparate(/*For color*/ GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                                    /*For alpha*/ GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

 

which was requested by someone who had a similar issue. Unfortunately it isn't working for me. I am afraid that I might need to do something involving stencil buffers and rendering the elements twice using two separate blend functions to get it to work, but I want to try to avoid that and find a simpler solution. Can anyone give me any pointers?

 

Here is the function I use for rendering GUI objects (some irrelevant code emitted):

void RenderingEngine::RenderGuiObjects()
{
	GuiRenderTheme* pCurGuiRenderTheme;
	ComponentMap* currentComponentMap = nullptr;
	glm::vec4* uvOffsetAndScale;

	glEnable(GL_DEPTH_TEST);

	//Prepare the gui drawing frame buffer for gui rendering.
	glBindFramebuffer(GL_FRAMEBUFFER,
			mpDrawBufferGui->GetFrameBufferObject());

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
			GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

	//todo: render by layer.

	for(unsigned int layer = 0; layer < 8; layer++)
	{
		for(unsigned int i = 0; i < mpGuiRenderingComponents->size(); i++)
		{
			mpActiveRenObjs->pCurRenComp = mpGuiRenderingComponents->at(i);

			if(mpActiveRenObjs->pCurRenComp->GetPaintAlgorithmLayer() == layer)
			{
				pCurGuiRenderTheme = mpActiveRenObjs->pCurRenComp->GetGuiRenderTheme();

				mpActiveRenObjs->pCurRenPosComp =
						 mpActiveRenObjs->pCurRenComp->GetTransformComponent();

				mpActiveRenObjs->curShaderProgram = mpShaderManager->
							 GetShaderObject(pCurGuiRenderTheme->shaderIndex);

				glUseProgram(mpActiveRenObjs->curShaderProgram);

				glBindVertexArray(
						*pCurGuiRenderTheme->pMesh->GetVertexArrayPtr());

			        uvOffsetAndScale =
						mpActiveRenObjs->pCurRenComp->GetPointerToUVOffsets();

				SendUniform(UNIFORM_MAT4F, "worldMatrix",
						mpActiveRenObjs->pCurRenPosComp->GetRawPtrWorldMatrix());
				SendUniform(UNIFORM_MAT4F, "viewMatrix",
						&mpImportantMatrices->guiViewMatrix);
				SendUniform(UNIFORM_MAT4F, "projectionMatrix",
						&mpImportantMatrices->guiProjectionMatrix);
				SendUniform(UNIFORM_VEC4F, "uv1OffsetAndScale",
						uvOffsetAndScale);

				SendUniform(UNIFORM_1F, "opacity",
						mpActiveRenObjs->pCurRenComp->GetOpacity());
				SendUniform(UNIFORM_1F, "hasTransparencyTexture", 0.0f);

				SendUniform(UNIFORM_1I, "diffuse", 0);

				ChangeTextureSlot(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D,
						pCurGuiRenderTheme->pMaterial->GetTextures()->at(0)->
						textureObject);

				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

				glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

			}
		}
	}
}

Also this is made with OpenGL 4.2 with c++ and compiled with MinGW.

Edited by Solid_Spy

Share this post


Link to post
Share on other sites
Advertisement

First of all you need to take a look into fragment shader (that one that draws your hud) you need to determine whenever fragment is transparent or not (and you write it as alpha value) after drawing that into fbo texture, you use single additive blending 

 
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

 //bind fbo texture
//draw fullscreen quad

glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);

 

anyway i dont see that you define viewport assumming that your fbo size is the ogl window size that could not work, better to use power of two texture size and then trim the texture

Edited by WiredCat

Share this post


Link to post
Share on other sites

You don't need any blend states on when drawing the HUD in it's own framebuffer, unless you are going to have UI pieces overlapping. All you need is a texture with alpha, and you plop ui elements into it by writing their rgba right into the rgba. Then when applying over the scene, you perform blending.

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!