C++ OpenGL - Overlay example - c++

I've an OpenGL application (maze style) that I need to work on as soon as possible. My problem at the moment is the following:
I've 3 subwindows on my main window and they are all working fine. Aparently I should be only using one subwindow and the left side subwindows (smaller ones) should be displayed as an overlay. My actual app has the following window display:
And I would like to go for something like this:
I've searched the internet and so far I've found nothing about this subject. Is there anywhere I can read about on how to solve this?
Thank you very much.

You could render the overlays to a texture, and then render this wherever you want on the screen. Look into the gl*FrameBuffer functions. It might look something like this:
// Create a texture to render to
glGenTextures(1, &overlay_tex);
glBindTexture(GL_TEXTURE_2D, overlay_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
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
// Attach the texture to the framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, overlay_tex, 0);
glGenRenderbuffers(1, &depth_rb);
glBindRenderbuffer(GL_RENDERBUFFER, depth_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
// Render your overlay here
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render to the backbuffer again

Related

Using glBlitFramebuffer to display a texture

I am trying to implement a simple multipass rendering scheme. I first blit the multisampled version of the scene to a FBO beforeEffectsContext.fbo. If I then blit this to the application provided FB it works fine. But I want to do another pass on the scene to blur it. I therefore bind the texture in the COLOR_ATTACHMENT0 in the beforeEffectsContext.fbo, sample it, drawing a quad with a blur effect added to another framebuffer blurContext.fbo.
If I know display the content of blurContext.fbo's color attachment to the screen using the same approach with a quad and a texture sampling, it works and I get a blurred scene.
But if I try to use glBlitFramebuffer() instead in this step, I get a black screeen. The problem seems to be in my misunderstanding of the blitting process and FBOs.
Initialization code for the blurContext.fbo:
// BeforeEffects Framebuffer
glGenFramebuffers(1, &renderContext->beforeEffectsContext.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, renderContext->beforeEffectsContext.fbo);
glGenTextures(1, &renderContext->beforeEffectsContext.colorAttachment);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderContext->beforeEffectsContext.colorAttachment);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderContext->beforeEffectsContext.colorAttachment, 0);
// Blur Framebuffer
glGenFramebuffers(1, &renderContext->blurContext.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, renderContext->blurContext.fbo);
glGenTextures(1, &renderContext->blurContext.colorAttachment);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderContext->blurContext.colorAttachment);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderContext->blurContext.colorAttachment, 0);
Rendering:
// Draw to the MSampled scene to the BeforeEffects framebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, renderContext->multiSamplingContext.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderContext->beforeEffectsContext.fbo);
glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
// Sample the texture attached to the beforeEffects FBO and draw to the blur FBO
glBindTexture(GL_TEXTURE_2D, renderContext->beforeEffectsContext.colorAttachment);
glBindFramebuffer(GL_FRAMEBUFFER, renderContext->blurContext.fbo);
glViewport(0, 0, 800, 600);
glUseProgram(renderContext->blurProgramContext.program);
glBindVertexArray(renderContext->vaoBlur);
glDrawArrays(GL_QUADS, 0, 4);
glUseProgram(0);
glBindVertexArray(0);
// Blit the content of the blur FBO to the app-provided Framebuffer (doesn't work, black screen)
glBindFramebuffer(GL_READ_FRAMEBUFFER, renderContext->blurContext.fbo);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_BUFFER, 0);
glViewport(0, 0, 800, 600);
glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
In the line where you are binding the default framebuffer (0) for drawing you have the target as GL_DRAW_BUFFER. According to https://www.opengl.org/sdk/docs/man/html/glBindFramebuffer.xhtml the correct enum for setting the draw framebuffer is GL_DRAW_FRAMEBUFFER. If you add a call to glGetError you will probably see a GL_INVALID_ENUM error.

OpenGL - FBO and alpha blending

I was finding for answer, but I can't get answer for my problem.
I have FBO and I can't get alpha blending and multisample to work. FBO draws scene to texture and then it's drown to default framebuffer with two textured triangles. Drawing directly to default framebuffer is fine.
Here is difference between default framebuffer (top) and my FBO (bottom).
I use FBO with 2x color attachments and 1x depth attachments. (Only GL_COLOR_ATTACHMENT0 is used, second is for other function)
Depth test: Disabled
Blending: Enabled
Multisample: Enabled
Blending function: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
Any ideas? What am I doing wrong? I can't blend any transparent objects, there is no alpha. If you require more code, I can edit post.
EDIT:
This code is deeper in code structure, I hope, I extracted it properly.
Setup FBO:
glGenFramebuffers(1, &_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color0_texture_id, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color1_texture_id, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture_id, 0);
Setup color texture:
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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);
Depth texture is the same except one line:
// This is probably wrong
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
EDIT:
Blending is working now, but still no multisample. How to do it?
To use multisampling when rendering to an FBO you need to allocate a multisample texture using glTexImage2DMultisample and attach that to the FBO using GL_TEXTURE_2D_MULTISAMPLE instead of GL_TEXTURE_2D.
Source: https://www.opengl.org/wiki/Multisampling#Allocating_a_Multisample_Render_Target

Retrieving final scene z-buffer and color buffer

I'm working on opengl 2.1 and opengl es 2.0. I want to implement Depth-of-field effect for whole scene. I know how to do this for single model with shader, but this would require all models to have shader with same code. Is there a way to retrieve final scene depth and color buffer and store them into textures so I could use them again with DOF shader? Or is it a bad idea?
[EDIT]
Finally got it working.
The initialization code looks like this:
glGenFramebuffers(1, &frameBuffer_);
glGenTextures(1, &colorBuffer_);
glGenTextures(1, &depthBuffer_);
//glGenRenderbuffers(1, &depthBuffer_);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer_);
glBindTexture(GL_TEXTURE_2D, colorBuffer_);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
width,
height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorBuffer_, 0);
glBindTexture(GL_TEXTURE_2D, depthBuffer_);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_DEPTH24_STENCIL8,
width,
height,
0,
GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, depthBuffer_, 0);
//glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer_);
//glRenderbufferStorage(
// GL_RENDERBUFFER,
// GL_DEPTH_COMPONENT24,
// width,
// height);
//glFramebufferRenderbuffer(
// GL_FRAMEBUFFER,
// GL_DEPTH_ATTACHMENT,
// GL_RENDERBUFFER, depthBuffer_);
GLenum status;
status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE:
// Success.
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
LOGE("Frame buffer format not supported.");
break;
default:
LOGE("Framebuffer Error.");
}
And later when rendering first call:
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer_);
Render scene, then call:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
And now anything can be rendered here using depthBuffer_ or colorBuffer_ as OpengGL texture handles.
Use a framebuffer object. They're part of OpenGL-ES-2 and are available as (well supported) extension to OpenGL-2.1.
See
https://github.com/datenwolf/codesamples/tree/master/samples/OpenGL/minimalfbo
for a minimal working example using extensions on desktop OpenGL-2.x

openGL FBO copy to texture results in black/dark image

In my program it is necessary for me to do off-screen rendering. For that purpose I use a FBO. In order to see if the image I draw is the correct for testing purposes I copy it from the FBO to a texture then render the texture to a quad. The problem is that when I copy from the FBO into the texture and render it the image appears dark/get a black color but the shapes are correct. I have tried using a texture as attachment in the FBO and rendering it directly (without copying it into another texture) and the colors are correct.
Below is the code for texture creation
//initial texture which works when rendered to a quad
glGenTexturesEXT(3, &textureID[0]);
glBindTextureEXT(GL_TEXTURE_2D, textureID[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
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_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 600, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
//second one which should be a copy of the above but has tha dark color mentioned
glBindTextureEXT(GL_TEXTURE_2D, textureID[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
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_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 600, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTextureEXT(GL_TEXTURE_2D, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D,textureID[0],0);
//Attach depth buffer to FBO
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb);
st1=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
Now in the rendering function
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //biding FBO
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//render code
unsigned char *pixels= new unsigned char [600*512*4];
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); //unbiding
glBindTextureEXT(GL_TEXTURE_2D,textureID[1]); //if I change to textureID[0] result is fine
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,600,512,0,GL_RGBA,GL_UNSIGNED_BYTE,pixels);
glBindTextureEXT(GL_TEXTURE_2D,0);
glViewport(0, 0, 600, 512);
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBindTextureEXT(GL_TEXTURE_2D, textureID[1]);
//setting the correct matrixes + render a quad
//before rendering a quad I set the color with
glColor3f(1.0, 1.0, 1.0);
delete[] pixels;
glutSwapBuffers();
I'm using glut for the setup. I have tried other functions such as glGetTexImage2D after unbiding the FBO and biding the texture as an alternative to glReadPixels(...) but with no success.
I don't understand this call to glTexImage2D in your second code snippet. pixels will contain just garbage. What do you expect it to do?
Textures have been core OpenGL for a very, very long time. It's just glGenTextures and glBindTexture not ...EXT. Also I recommend to either use ...ARB versions of the FBO functionality, or just using OpenGL core framebuffer support (of later OpenGL versions).

Framebuffer Object creation error

EDIT: SOLVED
I encountered a problem while attempting to render into a texture. I create a framebuffer object like this:
glGenTextures(1, &renderFBOtex);
glBindTexture(GL_TEXTURE_2D, renderFBOtex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &renderFBOrender);
glBindRenderbuffer(GL_RENDERBUFFER, renderFBOrender);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &renderFBO);
glBindFramebuffer(GL_FRAMEBUFFER, renderFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderFBOtex, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderFBOrender);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
But the return value of glCheckFrambufferStatus is always GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.
The problem seems to be with the texture, as it is the same without the Renderbuffer attachment. Drawing into the Framebuffer itself shouldn't be a problem.
Could someone please point out what am I missing here?
Build texture mipmaps before attaching it on the color buffer.
The routine dedicated to this task is glGenerateMipmap.
Another suggestion would be to play with the texture internal format. You are not specifying a sized internal format. Since one of reason of the error is that the texture doesn't have a supported color-renderable internal format, you could give a try.
Problem was in another part of the program. It was a very stupid mistake, which led to use of wrongly initialized values for width and height of the texture. They were both set to 0, hence the incomplete attachment error.
Try this:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderFBOtex, 0);
^^^^
Technically they should make no difference, but some drivers may had this bug.