You can specify what buffers to draw to using
glDrawBuffer()
example
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers( 1, buffers );
ok so that makes sense.
how about the depth texture though?
so we have here our creation of a frame buffer
glGenFramebuffers(1, &m_uifboHandle);
// Initialize FBO
glBindFramebuffer(GL_FRAMEBUFFER, m_uifboHandle);
unsigned int m_uiTextureHandle[2];
glGenTextures( 2, m_uiTextureHandle );
glBindTexture( GL_TEXTURE_2D, m_uiTextureHandle[x]);
// Reserve space for our 2D render target
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);
glTexImage2D(GL_TEXTURE_2D, 0, iInternalFormat, uiWidth, uiHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTextureHandle[0], 0);
//now the depth
glBindTexture(GL_TEXTURE_2D, m_uiTextureHandle[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, uiWidth, uiHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_uiTextureHandle[1], 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
so if these steps basically:
1) make an frame to manipulate to render to
2) gives us a location for attachment 0 to write to
3) creates our depth attachment
now how can i write to it? i seen examples where rendering automatically renders to it but i want to understand how binding to write to it works.
glDrawBuffers is not related to the depth buffer at all. It allows selecting the color buffers to render into, and there can be more than one color buffer per framebuffer. But there can be at most one depth buffer. So either there is no depth buffer at all, or there is one and the depth value is written to the depth buffer (assuimg depth test is enabled and the depth mask is set to GL_TRUE).
Related
This is the part of bigger project basically, I'm Creating Framebuffer with color, depth and stencil buffer in a following way:
// Create texture
glGenTextures(1, &m_textureInput);
glBindTexture(GL_TEXTURE_2D, m_textureInput);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWidth(), getHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
// Create FBOs
glGenFramebuffers(1, &m_fboInput);
glBindFramebuffer(GL_FRAMEBUFFER, m_fboInput);
// Attach texture to it
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textureInput, 0);
// Render buffer, depth with stencil
glGenRenderbuffers(1, &m_rbDepthStencilInput);
glBindRenderbuffer(GL_RENDERBUFFER, m_rbDepthStencilInput);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, getWidth(), getHeight());
//Attach depth buffer to FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_rbDepthStencilInput);
//Also attach as a stencil
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_rbDepthStencilInput);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
{
// Restore current framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
I bind it to render to it with:
glBindFramebuffer(GL_FRAMEBUFFER, m_fboInput);
// render
glBindFramebuffer(GL_FRAMEBUFFER, 0);
When i dump attached texture with:
glBindTexture(GL_TEXTURE_2D, m_textureInput);
long imageSize = x * y * 4;
unsigned char *data = new unsigned char[imageSize];
glReadPixels(0,0,x,y, GL_BGRA,GL_UNSIGNED_BYTE,data);
i receive content of main framebuffer (0).
Any idea what I'm dong wrong?
Thanks in advance.
glReadPixels docs say it reads data from the framebuffer. since you bound zero to it before, my guess would be it reads from the default framebuffer.
you can either bind your framebuffer object, then call glReadBuffer with GL_COLOR_ATTACHMENT0 and then do glReadPixels or, maybe more straight forward, use glGetTexImage to directly read from your texture.
So as a final step in my deferred shader I've been trying to get a skybox to work. Essentially I go through all the regular deferred shader steps and then use some post processing stuff like HDR and bloom, this final step is rendered to a full screen quad using a forward shader. Now if I just render the skybox separately or the deferred shading results everything looks fine and normal. It's when I try to render the skybox last that it doesn't end up on the screen.
So basically after I render the quad with the results I want to render the skybox using the depth values from the geometry pass. I've tried blitting the depth buffer as Deferred Rendering Skybox OpenGL suggests but it doesn't have any effect and I think the issue is with how I set up my depth buffer for the FBO since it shares a stencil attachment.
My render call for the skybox:
//draw skybox
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, mWindowWidth, mWindowHeight, 0, 0, mWindowWidth, mWindowHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Draw skybox as last
glDepthFunc(GL_LEQUAL); // Change depth function so depth test passes when values are equal to depth buffer's content
ShaderMan.bindShader(SKY_BOX_SHADER);
glm::mat4 view = glm::mat4(glm::mat3(CameraMan.getActiveCamera()->getViewMatrix())); // Remove any translation component of the view matrix
glm::mat4 projection = CameraMan.getActiveCamera()->getProjectionMatrix();
glUniformMatrix4fv(ShaderMan.getActiveShader().getUniformLocation("viewMatrix"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(ShaderMan.getActiveShader().getUniformLocation("projectionMatrix"), 1, GL_FALSE, glm::value_ptr(projection));
// skybox cube
glUniform1i(ShaderMan.getActiveShader().getUniformLocation("skybox"), 0);
mSkybox.render();
glDepthFunc(GL_LESS); // Set depth function back to default
ShaderMan.unbindShader();
and how I set up the deferred FBO
//POSIITON
glGenTextures(1, &mPositionTexture);
glBindTexture(GL_TEXTURE_2D, mPositionTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, mWindowWidth, mWindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
//Nearest min mag filters since we dont want interpolated values
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
//glFrameBuffer attaches a texture as a color attachment, depth attachment or stencil etc
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mPositionTexture, 0);
glGenTextures(1, &mNormalTexture);
glBindTexture(GL_TEXTURE_2D, mNormalTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, mWindowWidth, mWindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mNormalTexture, 0);
//Combined color and specular buffer
glGenTextures(1, &mSpecularAlbedoTexture);
glBindTexture(GL_TEXTURE_2D, mSpecularAlbedoTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, mWindowWidth, mWindowHeight, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mSpecularAlbedoTexture, 0);
//Depth & stencil texture for the FBO
glGenTextures(1, &mDepthTexture);
glBindTexture(GL_TEXTURE_2D, mDepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, mWindowWidth, mWindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, mDepthTexture, 0);
// final
glGenTextures(1, &mFinalTexture);
glBindTexture(GL_TEXTURE_2D, mFinalTexture);
///Used to be GL_RGBA only
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, mWindowWidth, mWindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, mFinalTexture, 0);
I'm thinking the GL_DEPTH_STENCIL_ATTACHMENT is what messes something up, but I also can't see why you shouldnt be able to blit the depth attachment if you specify it in the blit function
An image of the result, no skybox: result
EDIT
I tried searching around a bit and changed the format to GL_DEPTH_24_STENCIL8 in case the main fbo had a different float format, but that did not help either.
You shouldn't attempt to blit an FBO depth buffer to the default depth buffer. To blit from one depth buffer to another the internal formats of both must be exactly the same. Whilst you can define the format of an FBO, the default depth buffer is implementation defined. You might be able to deduce its format by trial and error but the solution will not be portable.
One solution would be to write out your depths to an R32F texture colour attachment during the geometry pass. Later when you're drawing your skybox to the default framebuffer you can bind the R32F texture to a sampler and read the depth for that pixel in the fragment shader. Only output the skybox to fragments where the depth is 0.0f.
The main steps for depth testing from my understanding:
1) enable depth testing and how we want to depth test
2) create the frame buffer object and make sure it has a depth attached to it
3) bind our frame buffer object ( make sure to clear it before rendering )
4) draw stuff
And that should be it no? our frame buffer depth attachment should have depth data? But I always get straight 1's default depth clear color
step 1:
glEnable(GL_DEPTH_TEST);
glDepthFunc( GL_LEQUAL );
step 2:
//create the frame buffer object
glGenFramebuffers(1, &m_uifboHandle);
// Initialize FBO
glBindFramebuffer(GL_FRAMEBUFFER, m_uifboHandle);
//create 2 texture handles 1 for diffuse, 1 for depth
unsigned int m_uiTextureHandle[2];
glGenTextures( 2, m_uiTextureHandle );
//create the diffuse texture
glBindTexture( GL_TEXTURE_2D, m_uiTextureHandle[0]);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, uiWidth, uiHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTextureHandle[0], 0);
.
//create the depth buffer
glBindTexture(GL_TEXTURE_2D, m_uiTextureHandle[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, uiWidth, uiHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_uiTextureHandle[1], 0);
//go back to default binding
glBindFramebuffer(GL_FRAMEBUFFER, 0);
step 3:
//bind the frame buffer object
glBindFramebuffer( GL_FRAMEBUFFER, m_uifboHandle );
//clear it
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
step 4:
//draw things
Are these not the steps?
Am i missing something?
I've tried a few different tutorials.
I can't get any depth to render to a texture
I keep getting straight 1's over and over.
The framebuffer probably is not complete. Try checking for completeness. Moreover your code was:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, uiWidth, uiHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
However, it should be (watch the RGB-RGBA):
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, uiWidth, uiHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
I am unable to read correct depth values from depth texture using glreadpixels function. FBO status is complete. other render targets also look fine after blitting to another FBO.
code snippet:
// Create the FBO
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// Create the gbuffer textures
glGenTextures(GBUFFER_NUM_TEXTURES, m_textures);
glGenTextures(1, &m_depthTexture);
for (unsigned int i = 0 ; i < GBUFFER_NUM_TEXTURES ; i++) {
glBindTexture(GL_TEXTURE_2D, m_textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, fboWidth, fboHeight, 0, GL_RGBA, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, m_textures[i], 0);
}
// depth
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, fboWidth, fboHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);
GLenum DrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(GBUFFER_NUM_TEXTURES, DrawBuffers);
GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE) {
printf("FB error, status: 0x%x\n", Status);
return 0;
}
// drawing something with depth test enabled.
// Now i am using glreadpixels functions to read depth values from depth texture.
int w = 4, h = 1;
GLfloat windowDepth[4];
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glReadPixels(x, y, w, h, GL_DEPTH_COMPONENT, GL_FLOAT, windowDepth);
You are drawing to a depth texture. The appropriate function to call to read a texture into client memory is glGetTexImage (...).
Now, since there is no glGetTexSubImage (...), you need to allocate enough client storage to hold an entire LOD of the depth texture. Something like this will probably do the trick:
GLuint w = fboWidth, h = fboHeight;
GLfloat windowDepth [w * h];
glBindTexture (GL_TEXTURE_2D, m_depthTexture);
glGetTexImage (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, windowDepth);
Keep in mind that unlike glReadPixels (...), glGetTexImage (...) does not perform pixel transfer conversion. That is, your format and data type must be an exact match with the types used when the texture was created, the GL will not convert your data.
With that out of the way, can I ask why you are reading the depth buffer into client memory in the first place? You appear to be using deferred shading, so I can see why you need a depth texture, but it is less clear why you need a copy of the depth buffer outside of shaders. You will have a hard time achieving interactive frame rates if you copy the depth buffer each frame.
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