Do not quite understand the operation render buffer object. For example if I want to show what is in the render buffer, I must necessarily do the render to texture?
GLuint fbo,color_rbo,depth_rbo;
glGenFramebuffers(1,&fbo);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glGenRenderbuffersEXT(1, &color_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, 256, 256);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,GL_RENDERBUFFER_EXT, color_rb);
glGenRenderbuffersEXT(1, &depth_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT, depth_rb);
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)!=GL_FRAMEBUFFER_COMPLETE_EXT)return 1;
glBindFramebuffer(GL_FRAMEBUFFER,0);
//main loop
//This does not work :-(
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawCube();
glBindFramebuffer(GL_FRAMEBUFFER,0);
any idea?
You are not going to see anything when you draw to an FBO instead of the default framebuffer, that is part of the point of FBOs.
Your options are:
Blit the renderbuffer into another framebuffer (in this case it would probably be GL_BACK for the default backbuffer)
Draw into a texture attachment and then draw texture-mapped primitives (e.g. triangles / quad) if you want to see the results.
Since 2 is pretty self-explanatory, I will explain option 1 in greater detail:
/* We are going to blit into the window (default framebuffer) */
glBindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
glDrawBuffer (GL_BACK); /* Use backbuffer as color dst. */
/* Read from your FBO */
glBindFramebuffer (GL_READ_FRAMEBUFFER, fbo);
glReadBuffer (GL_COLOR_ATTACHMENT0); /* Use Color Attachment 0 as color src. */
/* Copy the color and depth buffer from your FBO to the default framebuffer */
glBlitFramebuffer (0,0, width,height,
0,0, width,height,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
GL_NEAREST);
There are a couple of things worth mentioning here:
First, blitting from one framebuffer to another is often measurably slower than drawing two textured triangles that fill the entire viewport. Second, you cannot use linear filtering when you blit a depth or stencil image... but you can if you take the texture mapping approach (this only truly matters if the resolution of your source and destination buffers differ when blitting).
Overall, drawing a textured primitive is the more flexible solution. Blitting is most useful if you need to do Multisample Anti-Aliasing, because you would have to implement that in a shader otherwise and multisample texturing was added after Framebuffer Objects; some older hardware/drivers support FBOs but not multisample color (requires DX10 hardware) or depth (requires DX10.1 hardware) textures.
Related
Use OpenGL (version 330) multisample, in QT framework.
The rendering image is like a star shape.
I use fragment shader to render the shape intensity on the black canvas.
I do not use OpenGL primitives.
When multisample is not used, and when the rendering output canvas has a smaller resolution (say 400x400 pixels), I can see aliasing effects along star shape edges.
If I increase the resolution, say 1500x1500 pixels, then the aliasing effects are much less obvious. So I think mutlisampling should be able to improve the result.
Now, in order to improve speed, I do not increase the resolution of the render buffer. Instead, I decide to try to use multisampling to reduce aliasing effects.
int num_samples = 2; // 4; // I guess the maximum for most graphic cards are 8
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, num_samples, GL_R11F_G11F_B10F, width, height, true );
GLuint fbo;
glGenFramebuffers( 1, &fbo );
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0 );
glViewport(0,0, width, height);
glEnable(GL_MULTISAMPLE);
// ... some code
// draw a rectangle, as it is 2D image processing
// OpenGL render program release
// now convert multisample frame buffer fbo to a regular frame buffer qopenglFramebufferOjbectP
// qopenglFramebufferOjbectP is QOpenGLFramebufferObject
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, qopenglFramebufferOjbectP->handle());
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
The whole code seems not to be totally wrong, since the output is the desired shape, except the anti aliasing effect.
The problem is:
Either I use multisample (with different sample numbers as 2 4, or 8), or I do not use multisample, the results are the same. I specially wrote the results out to images, and compared them side by side.
But if multisampling takes effect, the results should be expected to have less aliasing effects than that when multismaple is not used.
I use fragment shader to render the shape intensity on the black canvas. I do not use OpenGL primitives.
The basic idea of multisampling is that you're doing the same number of fragment shader invocations as non-multisampling, but a particular fragment only writes the outputs to specific samples in each pixel based on the geometry of the primitives you render. You are rendering what I presume is a quad; any apparent geometry is a fiction created by the fragment shader. Hence you have gained no benefit from the technique.
Imposter-based techniques don't usually benefit from multisampling.
There are ways to handle this, of course. The most obvious is to turn on per-sample shading, but this also effectively turns multisampling into super-sampling. That is, it isn't cheap.
A better idea would be to explicitly output a coverage mask with gl_SampleMask. It's not easy and it depends on how you generate your geometry. The idea is to, for each sample that a fragment covers, detect if that sample is within the imposter-generated geometry. If so, set that sample's mask to 1; if not, set it to 0. Thus, you generate 1 output value, and it is broadcast to the non-zero samples.
Both this and per-sample shading require GL 4.0+ (or ARB_sample_shading).
I created a Renderbuffer, that's then modified in OpenCL.
//OpenGL
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 600, 600);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
//OpenCL
renderEngine = new OpenCLProgram("render.cl");
renderEngine->addArgumentGLRBuffer(colorRenderbuffer);
How would I then proceed drawing my OpenCL creation, the buffer to the screen? I could bind it to a texture and draw a quad the size of my window, but I am not that sure, if it is the most efficient way. Also, if there was a better way of drawing to the screen from OpenCL, that would help!
The call you're looking for is glBlitFramebuffer(). To use this, you bind your FBO as the read framebuffer, and the default framebuffer as the draw framebuffer:
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, srcWidth, srcHeight, 0, 0, dstWidth, dstHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
Adjust the parameters for your specific use based on the linked man page.
This is preferable over writing your own shader and rendering a screen sized quad. Not only is it simpler, and requires fewer state changes, it can also be more efficient. Knowing that a blit operation needs to be performed gives the implementation a chance to use a more efficient path. For example, where present, it could use a dedicated blit engine that can run asynchronously to the general rendering functionality of the GPU.
Whether you should use a renderbuffer or texture is not as clear cut. Chances are that it won't make much of a difference. Still, I would recommend to use a renderbuffer as long as that's all you need. Because it has more limited functionality, the driver has the option to create a memory allocation that is more optimized for the purpose. Rendering to a renderbuffer can potentially be more efficient than rendering to a texture on some hardware, particularly if your rendering is pixel output limited.
Don't make it a renderbuffer.
OpenGL renderbuffers exist for the sole purpose of being render targets. The only OpenGL operations that read from them are per-sample operations during rendering to the framebuffer, framebuffer blits, and pixel transfer operations.
Use a texture instead. There is no reason you couldn't create a 600x600 GL_RGBA8 2D texture.
This is my first attempt to do multisampling (for anti-aliasing) with opengl. Basically, I'm drawing a background to the screen (which should not get anti-aliased) and subsequently I'm drawing the vertices that should be anti-aliased.
What I've done so far:
//create the framebuffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//Generate color buffer:
glGenRenderbuffers(1, &cb);
glBindRenderbuffer(GL_RENDERBUFFER, cb);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, x_size, y_size);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cb);
//Generate depth buffer:
glGenRenderbuffers(1, &db);
glBindRenderbuffer(GL_RENDERBUFFER, db);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT, x_size, y_size);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, db);
...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//draw background ... ...
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//draw things that should get anti-aliased ... ...
//finally:
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, x_size, y_size, 0, 0, x_size, y_size, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
The problem is: when I call glBlitFramebuffer(...) the whole background gets black and I only see the anti-aliased vertices.
Any suggestions?
Normally, blending is the most obvious option if you want to render a new image/texture on top of existing rendering while taking transparency in the image into account. Looking at the rendering into the multisampled framebuffer as an image with transparency, that's exactly the situation you have.
In this case, there are a couple of challenges that make the use of blending more difficult than usual. First of all, glBlitFramebuffer() does not apply blending. From the spec:
Blit operations bypass the fragment pipeline. The only fragment operations which affect a blit are the pixel ownership test and the scissor test.
Without multisampling in play, this is fairly easy to overcome. Instead of using glBlitFramebuffer(), you perform the blit by drawing a screen sized textured quad. Since all fragment operations are in play now, you could use blending.
Howerver, the "drawing a textured quad" part gets much trickier since your content is multisampled. A few options come to mind.
Render background to FBO
You could render the background to the multisampled FBO instead of the primary framebuffer. Then you can use glBlitFramebuffer() exactly as you do now.
You may think: "But I don't want my background to be anti-aliased!" That's not really a problem. You simply disable multisampling while drawing the background:
glDisable(GL_MULTISAMPLE);
I think that should give you what you want. And if it does, it's by far the easiest option.
Multisample Textures
OpenGL 3.2 and later support multisample textures. For this, you would use a texture instead of a renderbuffer as the color buffer of your FBO. The texture is allocated with:
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8,
xsize, ysize, GL_FALSE);
There are other aspects that I can't all cover here. If you want to explore this option, you can read up on all the details in the spec or other sources. For example, sampling of the texture in the shader code works differently, with a different sampler type, and sampling functions that only allow you to read one sample at a time.
Two-Stage Blitting
You could use a hybrid of glBlitFramebuffer() for resolving the multisample content, and the "manual" blit for blending the content into the default framebuffer:
Create a second FBO where the color attachment is a regular, not multisampled texture.
Use glBlitFramebuffer() to copy from multisampled renderbuffer in first FBO to texture in second FBO.
Set up and enable blending.
Draw a screen sized quad using the texture that was the attachment to the second FBO.
While this seems somewhat awkward, and requires an extra copy which is undesirable for performance, it is fairly straightforward.
Render the background last
For this, you do exactly what you're doing now, copying the multisampled FBO content to the default framebuffer with glBlitFramebuffer(). But you do this first, and render the background afterwards.
You may think that this wouldn't work because it puts the background in front of the other content, which makes it... not much of a background.
But here is where blending comes into play again. While blending content on top of other content is the most common way of using blending, you can also use it to render things behind existing content. To do this, you need a few things:
A framebuffer with alpha planes. How you request that depends on the window system/toolkit you use for your OpenGL setup. It's typically in the same area where you request your depth buffer, stencil buffer (if needed), etc. It is often specified as a number of alpha planes, which you typically set to 8.
The right blend function. For front to back blending, you typically use:
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
This adds the new rendering where nothing was previously rendered (i.e. the alpha in the destination is 0), and will keep the previous rendering unchanged where there was already rendering (i.e. the destination alpha is 1).
The blending setup can get a little trickier if your rendering involves partial transparency.
This may look somewhat complicated, but it's really quite intuitive once you wrap your head around how the blend functions work. And I think it's overall an elegant and efficient solution for your overall problem.
windows
using glew
I'm trying to render offscreen and save the img opengl rendered to a png file.
I followed a highly rated answer on stackoverflow:
How to render offscreen on OpenGL?
But the png file I get is only a black screen.
Here's my code relating to it:
glutCreateWindow(argv[0]);
if(GLEW_OK!=glewInit())
{
return -1;
}
initScene();
GLuint fbo, render_buf;
glGenFramebuffers(1,&fbo);
glGenRenderbuffers(1,&render_buf);
glBindRenderbuffer(GL_RENDERBUFFER,render_buf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, viewport.w, viewport.h);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fbo);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buf);
//Before drawing
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fbo);
glClear(GL_COLOR_BUFFER_BIT); // clear the color buffer
glMatrixMode(GL_MODELVIEW); // indicate we are specifying camera transformations
glLoadIdentity(); // make sure transformation is "zero'd"
//draw...
//glBegin(GL_POINTS) glColor3f, glVertex2f
//glFlush();
glFinish();
/*glutDisplayFunc(myDisplay);
glutPostRedisplay();*/
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
savePNG(outputPNGName,0,0,viewport.w,viewport.h);
//At deinit:
glDeleteFramebuffers(1,&fbo);
glDeleteRenderbuffers(1,&render_buf);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);
How to solve the problem?
Thank you
savePNG (related code):
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)image);
There are at least two problems in this code:
GL_RGB8 is not a valid format for a renderbuffer. From the glRenderbufferStorage() man page:
internalformat specifies the internal format to be used for the renderbuffer object's storage and must be a color-renderable, depth-renderable, or stencil-renderable format.
Table 8.13 in the latest spec document (4.5, downloadable from https://www.opengl.org/registry) lists all formats, with a column showing which of them are color-renderable. RGB8 does not have a checkmark in that column. You can use GL_RGBA8 instead, which is color-renderable.
You may also want to check out the glCheckFramebufferStatus() function, which allows you to check if your framebuffer setup is valid.
While we don't see the code for savePNG(), there is no way it can know that you want to read the pixel data from your FBO. It will most likely use glReadPixels(), which reads data from the current read framebuffer, while your code only sets the draw framebuffer. Before calling savePNG(), add this call to set the read framebuffer to your FBO:
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
I am trying to configure a Frame buffer object with depth buffer that has 32 bits, render to that and then merely copy the resulting color buffer to the system color buffer.
Can someone help me how to code this?
You can attach a texture:
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,
width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_,
textureId, level);
to an FBO and then use this texture to draw a full-screen quad on the screen.
rendering to a texture and then using fullscreen quad:
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/
By using this GL_DEPTH_COMPONENT24 you will have max depth precision that hardware uses.
In the fragment shader (for the fullscreen quad) you can read from such texture and use it as a gray scale image.
here is another related question: How to visualize a depth texture in OpenGL?
On the other hand if you want to have 32 bit buffer... maybe it is easier to use GL_R32F texture and calculate depth values in fragment shader. That way you will have better control over that process.