OpenGL not drawing nearest fragment to the camera - opengl

I have a scene with a teapot mesh in it.
I'm using a framgment shader to light it using a source of light whose value is equal to 10.
When the scene is rendered to the default framebuffer, everything seems to be fine.
But, if it's rendered in a custom framebuffer, the result looks like this :
OpenGL seems to prefer triangles defined "at the end of" the mesh.
I want the framebuffer to contain 16bits floats so I can store values larger than 1.0.
Sorry for my English.

I forgot to add a depth renderBuffer and clear it using glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
To do so, add :
GLuint rboDepth;
glGenRenderbuffers(1, &rboDepth);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width(), height());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
to your framebuffer implementation while it's bound.

Related

Multisampling with glBlitFramebuffer

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.

Draw the contents of the render buffer Object

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.

Incorrect-Reversed Backface Culling?

glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
I have been trying to implement deferred rendering for 2 weeks. But all of the meshes in my test program are culled reversely. The code above should be the correct way to render a model. Every example i looked at draws the objects like that. But here is the result when i use GL_BACK as cull face:
And this is the GL_FRONT:
GL_FRONT should have been the result i expected from GL_BACK. Strange thing is when I set glFrontFace to GL_CW, everything disappears. So this problem is not about winding. I spent all my day on searching information about this. Only thing i found is something about depth buffers. But I can't see any problems in creation. Just because of this problem, I can't correctly do stencil pass for spot light rendering. I enable GL_DEPTH_TEST in geometry pass. This is what i attach to my fbo as depth buffer
glGenRenderbuffers(1, &depthTexture);
glBindRenderbuffer(GL_RENDERBUFFER, depthTexture);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthTexture);
The main question is, what are the possibilities that would cause a reversed backface culling ?

What user's framebuffer lacks?

Here is a comparison of same object using framebuffer texture projected onto screen and "main framebuffer"
Left image is bit blured while right is more sharp.Alos some options like glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ) do not work properly while rendering into the framebuffer.
My "pipeline" looks like this
Bind frambuffer
draw all geometry
Unbind
Draw on Quad like as texture.
So I wondering why "main frambufffer" can do this while "mine" can't? What are the differences between those two? Does user framebuffers skips some stages? Is it possible to match the quality of main buffer?
void Fbo::Build()
{
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
renderTexId.resize(nColorAttachments);
glGenTextures(renderTexId.size(),&renderTexId[0]);
for(int i=0; i<nColorAttachments; i++)
{
glBindTexture(format,renderTexId[i]);
glTexParameterf(format, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(format, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(format, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(format, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(format, 0, type, width, height, 0, type, GL_FLOAT, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,renderTexId[i], 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
if(hasDepth)
{
glGenRenderbuffers(1, &depthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, depthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
//glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24, width, height, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferId);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
printf("FBO error, status: 0x%x\n", status);
}
}
Your "projection" of the FBO onto the screen is subject to sampler state, in particular the texture filter state is to blame here.
By default, if you simply bind the texture attachment you drew into from your FBO to a texture unit and apply it, it is going to use LINEAR sampling. This is different from blitting directly to the screen as would traditionally be the case if you were not using an FBO.
Default State table for Samplers in OpenGL:
http://www.opengl.org/registry/doc/glspec44.core.pdf pp. 541, Table 23.18 Textures (state per sampler object)
If you want to replicate the effect of drawing without an FBO, you would want to stretch a quad (or two triangles) over your viewport and use NEAREST neighbor sampling for your texture filter. Otherwise, it is going to sample adjacent texels in your FBO and interpolate them for each pixel on screen. This is the cause of your smoother image on the left side, which illustrates a form of anti-aliasing. It is worth mentioning that this is not even close to the same thing as MSAA or SSAA, which increase the sample rate when geometry is rasterized to fix undersampling errors, but it does achieve a similar effect.
Sometimes this is desirable, however. Many processing intensive algorithms run at 1/4, 1/8, or lower resolution and then use a bilinear or bilateral filter to upsample to the viewport resolution without the blockiness associated with nearest neighbor sampling.
The polygon mode state should work just fine. You will need to remember to set it back to GL_FILL before you draw your quad over the viewport though. Again, it all comes back to state management here - your quad will require some very specific states to produce consistent results. To render this way effectively you will probably have to implement a more sophisticated state management system / batch processor, you can no longer simply set glPolygonMode (...) once globally and forget it :)
UPDATE:
Thanks to datenwolf's comments, it should be noted that the above discussion of texture filtering was under the assumption your FBO was at a different resolution than the viewport you were trying to stretch it over.
If your FBO and viewport are at the same resolution, and you are still getting these artifacts from LINEAR texture filtering, then you have not setup your texture coordinates correctly. The problem in this scenario is that you are sampling your FBO texture at locations other than the texel centers and this is causing interpolation where none should be necessary.
Fragments are sampled at their centers (non-multisample) in GLSL by default, so if you setup your vertex texture coordinates and positions correctly you will not have to do any texel offset math on your per-vertex texture coordinates. Perspective projection can ruin your day if you are trying to do 1:1 mapping though, so you should either use orthographic projection, or better yet use NDC coordinates and no projection at all when you draw your quad over the viewport.
You can use the following vertex coordinates in Normalized Device Coordinates: (-1,-1,-1), (-1,1,-1), (1,1,-1),(1,-1,-1) for the 4 corners of your viewport if you replace the traditional modelview / projection matrices with an identity matrix (or simply do not multiply the vertex position by any matrix in your vertex shader).
You should also use CLAMP_TO_EDGE as your wrap state, because this will ensure you never generate texture coordinates outside the range of the center of the first texel and the center of the last texel in a given direction (s,t). CLAMP will actually generate values of 0 and 1 (which are not texel centers) for anything at or beyond the edges of the FBO texture attachment.
As a bonus, if you ALWAYS intend to render at 1:1 (FBO vs. viewport), you can avoid using per-vertex texture coordinates altogether and use gl_FragCoord. By default in GLSL, gl_FragCoord will give you the coordinate for the fragment center (0.5, 0.5), which also happens to be the corresponding texel center in your FBO. You can pass gl_FragCoord.st directly to your texture lookup in this special case.

Using openGL's glBindFramebuffer seems to have no effect

I am getting into FBOs (Framebuffer Objects) in openGL. Right now, I'm simply trying to render something to an FBO, then use the texture associated with it to render that image to the screen. I have been working on this problem for hours today and yesterday. I've tried copying as closely as I can two different examples, and yet I still have the same problem. I am absolutely stuck.
It seems like what is happening is that the framebuffer object is not actually being binded. In the code, I have two sets of glClear() and glClearColor() commands: the first for drawing to the framebuffer, and the second for drawing to the screen. However, when I comment out the second set, the first set is clearly affecting the screen. If the FBO is binded, shouldn't it receive those commands, and not affect the actual output to the screen directly?
To begin, I use glewInit(), and then I create an FBO, and then a Renderbuffer object and a texture to associate with it, and do all of the necessary steps to put it all together:
glewInit();
int width=512,height=512;
glGenFramebuffers(1, &fbo);
glGenRenderbuffers(1, &rbo);
glGenTextures(1, &fboTex);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindTexture(GL_TEXTURE_2D, fboTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_INT, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
assert(status==GL_FRAMEBUFFER_COMPLETE);
glBindTexture(GL_TEXTURE_2D,0);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
Then, I draw to the framebuffer object.
glClearColor(0.5,0.5,0.5,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glColor4f(1.0,0,0,1);
glBegin(GL_QUADS);
glVertex2f(100,100);
glVertex2f(200,100);
glVertex2f(200,250);
glVertex2f(100,200);
glEnd();
I then unbind each of the following three objects:
glBindFramebuffer(GL_FRAMEBUFFER,0);
glBindRenderbuffer(GL_RENDERBUFFER,0);
glBindTexture(GL_TEXTURE_2D,0);
Then I attempt to draw the texture to the window:
glEnable(GL_TEXTURE_2D);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTextureEXT(GL_TEXTURE_2D, fboTex);
glBegin(GL_QUADS);
glTexCoord2f(0,0);glVertex3f(-.5,-.5,0);
glTexCoord2f(1,0);glVertex3f(.5,-.5,0);
glTexCoord2f(1,1);glVertex3f(.5,.5,0);
glTexCoord2f(0,1);glVertex3f(-.5,.5,0);
glEnd();
glDisable(GL_TEXTURE_2D);
glFlush();
This has got to be either some really simple mistake or misunderstanding that somehow evaded eradication when I retyped all this twice, or a driver issue? My driver is supposed to be able to run version 3.2 of openGL...
Any help on this frustrating issue would be great.
EDIT: I found out what I was ultimately doing wrong. I didn't realize that glColor commands affected any drawing done, regardless of whether you have a framebuffer binded at the time or not. I needed to change the glColor back to (1,1,1) after drawing to the FBO, in order to render the FBO's texture later with all of its color.
Without a full code example it's difficult to see what's wrong. For kickstarting your FBO endeavors I provide https://github.com/datenwolf/codesamples/tree/master/samples/OpenGL/minimalfbo