I want to achieve a post process outline effect on some actors in my game and I want the outline be occluded by other actors closer to the camera. To do so I planed to render the elements that should be outline in an FBO and an outline shader. To discard the pixel that are occluded I want to use the depth buffer of the default framebuffer.
I read and searched but I didn't find how to properly use the default framebuffer depth buffer in another framebuffer or how to copy or anyway to use the default depth buffer informations on an fbo.
How can I achieve it?
I read and searched but I didn't find how to properly use the default framebuffer depth buffer in another framebuffer
Unfortunately, there is no way in OpenGL to do that.
or how to copy or anyway to use the default depth buffer informations on an fbo.
That is quite easy. Just create an FBO with a appropriate depth attachment (no matter if texture or renderbuffer), and blit the default depth buffer to it:
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, your_target_fbo);
glBlitFramebuffer(0,0,width,height,0,0,width,height,GL_DEPTH_BUFFER_BIT, GL_NEAREST);
However, since you do some post-processing anyway, it might be a good option to render the intial scene into an FBO and re-use the same depth buffer in different FBOs.
Unfortunately, it is not possible to attach the default depth-buffer to a FBO or to read it from a shader.
You can copy the default framebuffer into a renderbuffer (or a framebuffer attached texturem, see glBlitFramebuffer), but this could be relatively slow.
Another option is to render the complete scene first to a FBO (color + depth), then use the outline shader to read from this FBO, combine the result with the outline calculation and write the final result to the default framebuffer.
Related
In order to implement "depth-peeling", I render my OpenGL scene in to a series of framebuffers each equipped with a rgba color texture and depth texture. This works fine if I don't care about anti-aliasing. If I do, then it seems the correct thing to do is enable GL_MULTISAMPLING and use a GL_TEXTURE_2D_MULTISAMPLE instead of GL_TEXTURE_2D. But I'm confused about which other calls need to be replaced.
In particular, how should I adapt my framebuffer construction to use glTexImage2DMultisample instead of glTexImage2D?
Do I need to change the calls to glFramebufferTexture2D beyond using GL_TEXTURE_2D_MULTISAMPLE instead of GL_TEXTURE_2D?
If I'm rendering both color and depth into textures, do I need to make a call to glRenderbufferStorageMultisample?
Finally, is there some glBlit* that I need to do in addition to setting up textures for the framebuffer to render into?
There are many related questions on this topic, but none of the solutions I found seem to point to a canonical tutorial or clear example putting all these together.
While I have only used multisampled FBO rendering with renderbuffers, not textures, the following is my understanding.
Do I need to change the calls to glFramebufferTexture2D beyond using GL_TEXTURE_2D_MULTISAMPLE instead of GL_TEXTURE_2D?
No, that's all you need. You create the texture with glTexImage2DMultisample(), and then attach it using GL_TEXTURE_2D_MULTISAMPLE as the 3rd argument to glFramebufferTexture2D(). The only constraint is that the level (5th argument) has to be 0.
If I'm rendering both color and depth into textures, do I need to make a call to glRenderbufferStorageMultisample?
Yes. If you attach a depth buffer to the same FBO, you need to use a multisampled renderbuffer, with the same number of samples as the color buffer. So you create your depth renderbuffer with glRenderbufferStorageMultisample(), passing in the same sample count you used for the color buffer.
Finally, is there some glBlit* that I need to do in addition to setting up textures for the framebuffer to render into?
Not for rendering into the framebuffer. Once you're done rendering, you have a couple of options:
You can downsample (resolve) the multisample texture to a regular texture, and then use the regular texture for your subsequent rendering. For resolving the multisample texture, you can use glBlitFramebuffer(), where the multisample texture is attached to the GL_READ_FRAMEBUFFER, and the regular texture to the GL_DRAW_FRAMEBUFFER.
You can use the multisample texture for your subsequent rendering. You will need to use the sampler2DMS type for the samplers in your shader code, with the corresponding sampling functions.
For option 1, I don't really see a good reason to use a multisample texture. You might just as well use a multisample renderbuffer, which is slightly easier to use, and should be at least as efficient. For this, you create a renderbuffer for the color attachment, and allocate it with glRenderbufferStorageMultisample(), very much like what you need for the depth buffer.
I would like to save the output of my image processing OpenGL shader program to an image file and also display the result on the screen. I know how to save the window framebuffer using glReadPixels(). However, the resolution of the screen is smaller than the dimensions of the image.
If I render to an FBO, do I need to call glDrawArrays() again after saving and unbinding the FBO to see the results on the screen? Or is it possible to tell the window framebuffer to render from the FBO without having to run the shader program a second time?
To save the rendered image in the RBO, you can read the pixels directly by setting which buffer OpenGL will read the pixels from by calling glReadBuffer. In your particular case, setting the read buffer to GL_COLOR_ATTACHMENT<i> should do the trick. See the glDrawBuffer man page for details.
In order to display the image in the FBO: yes, you will need to make an additional rendering pass to copy the FBO's image into the default frame buffer. You an either bind the FBO as a texture, and render geometry, as you suggest, to get the image on the screen, or, you may be able to use glBlitFramebuffer to simplify the copying and image filtering.
If I render to an FBO, do I need to call glDrawArrays() again after saving and unbinding the FBO to see the results on the screen?
You should use glBlitFramebuffer (...), the purpose of this function is to copy one framebuffer (read buffer) to another (draw buffer). Provided you are not doing something unusual like drawing into an integer texture attachment then your FBO's draw buffer should be compatible with your default framebuffer (window).
There are some additional caveats related to the filter method and the type of image you are copying (e.g. depth buffers cannot use linearly interpolation), but since you are discussing "full scale" here, I imagine you are interested in GL_NEAREST anyway.
In DirectX you are able to have separate render targets and depth buffers, so you can bind a render target and a depth buffer, do some rendering, remove the depth buffer and then do more rendering using the old depth buffer as a texture.
How would you go about this in opengl? From my understanding, you have a framebuffer object that contains both the color buffer(s) and an optional depth buffer. I don't think I can bind several framebuffer objects at the same time, would I have to recreate the framebuffer object every time it changes(probably several times a frame)? How do normal opengl programs do this?
A Framebuffer Object is nothing more than a series of references to images. These can be images in Textures (such as a mipmap layer of a 2D texture) or Renderbuffers (which can't be used as textures).
There is nothing stopping you from assembling an FBO that uses a texture's image for its color buffer and a texture's image for its depth buffer. Nor is there anything stopping you from later (so long as you're not rendering to that FBO while doing this) sampling from the texture as a depth texture. The FBO does not suddenly own these images exclusively or something.
In all likelihood, what has happened is that you've misunderstood the difference between an FBO and OpenGL's Default Framebuffer. The default framebuffer (ie: the window) is unchangeable. You can't take it's depth buffer and use it as a texture or something. What you do with an FBO is your own business, but OpenGL won't let you play with its default framebuffer in the same way.
You can bind multiple render targets to a single FBO, which should to the trick. Also since OpenGL is a state machine you can change the binding and number of targets anytime it is required.
Shaders can not read data from framebuffer, they can pass data only forward by rendering pipeline. But for post-processing it is needed to read rendered image.
I'm going to resolve this as following: 1) create a texture with size of viewport; 2) render image to the texture normally; 3) render the texture to framebuffer passing it through post-processing shader.
Am I doing right? Are there more effective ways to do post-processing?
That is indeed the usual way to do post-processing ! Render to texture by binding an FBO for your first pass, then use that texture as the input of your post-process shader after unbinding your FBO (i.e. returning to the default frame buffer).
Here's the situation: I have a texture containing some depth values. I want to render some geometry using that texture as the depth buffer, but I want the color to be written to the normal framebuffer (i.e., the window's framebuffer).
How do I do this? I tried creating an FBO and only binding a depth texture to it (GL_DEPTH_COMPONENT) but that didn't work; none of the colors showed up.
No you can't. The FBO you are rendering to may be either a main framebuffer or an off-screen one. You can't mix them in any way.
Instead, I would suggest you to render to a color renderbuffer and then do a simple blitting operation into the main framebuffer.
Edit-1.
Alternatively, if you already have depth in the main FB, you can first blit your depth and then render to a main FB, thus saving video memory on the additional color renderbuffer.
P.S. Blitting is done via glBlitFramebuffer. In order to make it work you should setup GL_READ_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER and glDrawBuffer() for each of them.