PDA

View Full Version : FBO with depth and 3 RGBA16F as output - issues



Pablo
09-23-2011, 01:27 PM
Hi there,
I'm using OpenGL 3.3 core profile and lately created a deferred renderer which tries to output data to depth texture and 3 GL_RGBA16F textures at once. Unfortunately I'm having some issues...
1. When I attach depth as a renderbuffer to the FBO, all 3 GL_RGBA16F targets are rendering without any problem. But because I need depth as a texture, so...
2. I attached depth as a texture to the FBO, and suddenly all I can do is watch the depth buffer and first color attachment rendered correctly, but the second and third are completely black...
My question - Is it correct to assume that I can mix those textures types (GL_DEPTH_COMPONENT with GL_RGBA16F) as attachments for the same FBO?

PS. I know from a doc posted about Starcraft 2 shading that guys from blizzard used 4 MRT, all RGBA FP16... Starcraft 2 is a Windows and Mac release, so I assume that Windows part is DX code, but Mac is OpenGL based, thus there must be a way to do this, but the question is how? Any ideas, directions?

PS.2. I'm using Windows 7 x64 with Nvidia GTX 280, and latest drivers (280.26).

PS.3. The way I create the FBO

glGenFramebuffers(1, &_frame_id);

// First RGBA16F
glGenTextures(1, &tex_id1);
glBindFramebuffer(GL_FRAMEBUFFER, _frame_id);
glBindTexture(GL_TEXTURE_2D, tex_id1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, _width, _height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_id1, 0);

// Second RGBA16F
glGenTextures(1, &tex_id2);
glBindFramebuffer(GL_FRAMEBUFFER, _frame_id);
glBindTexture(GL_TEXTURE_2D, tex_id2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, _width, _height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex_id2, 0);

// Depth
glGenTextures(1, &tex_id3);
glBindFramebuffer(GL_FRAMEBUFFER, _frame_id);
glBindTexture(GL_TEXTURE_2D, tex_id3);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, _width, _height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex_id3, 0);

PS.4. vert & frag shaders

// Vertex shader
#version 330 core

#define POSITION 0
#define NORMAL 1
#define TEXCOORD 2
#define TANGENT 4

layout(location = POSITION) in vec4 Position;
layout(location = NORMAL) in vec3 Normal;
layout(location = TEXCOORD) in vec2 Texcoord;
layout(location = TANGENT) in vec4 Tangent;

uniform mat4 MVP;
uniform mat3 NM;

out block
{
vec2 Texcoord;
mat3 TBN;
} Out;

void main(void)
{
Out.Texcoord = Texcoord;

vec3 _normal = normalize(NM * Normal);
vec3 _tangent = normalize(NM * Tangent.xyz);
vec3 _binormal = normalize(-Tangent.w * cross(Normal, Tangent.xyz));

Out.TBN = mat3(_tangent.x, _binormal.x, _normal.x,
_tangent.y, _binormal.y, _normal.y,
_tangent.z, _binormal.z, _normal.z);

gl_Position = MVP * Position;
}

// Fragment shader
#version 330 core

#define POSITION 0
#define TEXCOORD 2

#define FRAG_COLOR 0

uniform sampler2D Diffuse;
uniform sampler2D Parallax;

in block
{
vec2 Texcoord;
mat3 TBN;
} In;

layout(location = FRAG_COLOR, index = 0) out vec4 outputColor[2];

void main(void)
{
vec4 normalMap = texture2D(Parallax, In.Texcoord);
vec3 n = normalize(2.0f * normalMap.rgb - 1.0f);
vec3 normal = n * In.TBN;

outputColor[0] = texture2D(Diffuse, In.Texcoord);
outputColor[1] = vec4(normalize(normal) * 0.5f + 0.5f, 1.0f);
}

Alfonse Reinheart
09-23-2011, 01:42 PM
I attached depth as a texture to the FBO

Presumably, you were getting this to work with a depth renderbuffer, yes? So are you saying that changing it to a texture with the same format was enough to break it?

Also, use internal formats with a specific size (GL_DEPTH_COMPONENT24, not GL_DEPTH_COMPONENT).

Pablo
09-23-2011, 02:43 PM
Hi Alfonse,
yes I was first doing this with renderbuffer, and color attachments where rendered correctly, after the switch to render depth to texture not renderbuffer I receive just first color attachment correctly, rest are black. As to the internal formats, I've tried all before even posting here, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32... Maybe it's something related to my shaders? Do I need to change the way I output colors if one of my output is depth texture?

Alfonse Reinheart
09-23-2011, 03:29 PM
You're still binding it to the depth attachment point, right? You didn't try to bind it to GL_COLOR_ATTACHMENTi.

Also, are you checking the FBO's completion state after setting it up?

Pablo
09-23-2011, 10:03 PM
Yes, as did I put the code of creating the textyres, I bind them this way (in reality it is my FBO class that creates this c style array of GLenum, and fills it with data):

GLenum buffers[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_DEPTH_ATTACHMENT
};
glDrawBuffers(3, buffers);

As to the FBO's completion state it returns GL_FRAMEBUFFER_COMPLETE.
I check the FBO status with this code:

GLenum status;

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _frame_id);
status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);

switch (status){
case GL_FRAMEBUFFER_COMPLETE:
printf("GL_FRAMEBUFFER_COMPLETE\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
printf("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
printf("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
printf("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
printf("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
printf("GL_FRAMEBUFFER_UNSUPPORTED\n");
break;
default:
printf("Unknown FBO error\n");
break;
}

for(int i = 0; i < int(_tex_id.size()); i++)
{
printf("FBO attachment ID: %d\n", i);
switch(_buffers[i])
{
case GL_COLOR_ATTACHMENT0:
printf("FBO attachment point: GL_COLOR_ATTACHMENT0\n");
break;
case GL_COLOR_ATTACHMENT1:
printf("FBO attachment point: GL_COLOR_ATTACHMENT1\n");
break;
case GL_COLOR_ATTACHMENT2:
printf("FBO attachment point: GL_COLOR_ATTACHMENT2\n");
break;
(...)
case GL_DEPTH_ATTACHMENT:
printf("FBO attachment point: GL_DEPTH_ATTACHMENT\n");
break;
case GL_STENCIL_ATTACHMENT:
printf("FBO attachment point: GL_STENCIL_ATTACHMENT\n");
break;
default:
printf("Unknown FBO attachment point\n");
break;
}
}
The log in my test app is this:

GL_FRAMEBUFFER_COMPLETE
FBO attachment ID: 0
FBO attachment point: GL_COLOR_ATTACHMENT0
FBO attachment ID: 1
FBO attachment point: GL_COLOR_ATTACHMENT1
FBO attachment ID: 2
FBO attachment point: GL_COLOR_ATTACHMENT2
FBO attachment ID: 3
FBO attachment point: GL_DEPTH_ATTACHMENT
I've tried to reduce the number of color attachments, their type to RGBA8 instead of RGBA16F, and the results are always the same - attachment 0 is OK, 1-2 are black, and the depth (id 2 or 3 depending on the attachment count) is OK.
To add even more informations - if I attach the depth as the first texture to the fbo:

GL_FRAMEBUFFER_COMPLETE
FBO attachment ID: 0
FBO attachment point: GL_DEPTH_ATTACHMENT
FBO attachment ID: 1
FBO attachment point: GL_COLOR_ATTACHMENT0
FBO attachment ID: 2
FBO attachment point: GL_COLOR_ATTACHMENT1
FBO attachment ID: 3
FBO attachment point: GL_COLOR_ATTACHMENT2

the depth is OK and all the color attachments except the first one are black.

Alfonse Reinheart
09-24-2011, 12:32 AM
glDrawBuffers(3, buffers);

That's wrong. You do not draw to the depth attachment. The only difference between rendering to a depth renderbuffer and rendering to a depth texture is the fact that you used glFramebufferTexture* rather than glFramebufferRenderbuffer() to attach the surface.

The depth attachment is the gl_FragData output from the fragment shader. It is not part of the draw buffers.

Pablo
09-24-2011, 01:35 AM
Thank You, I didn't know that... I fixed that it is not attached and everything works as expected... I didn't thought about it :p Heh, I guess that I got a lil bit rusty, cause I sat few days ago to write this core gl3.3 deferred renderer just for fun and I did not code anything in like 3-4 years... Much has changed, but I'm a fast learner and this community is great, so I think all of You can expect a nice open source app soon.

PS. With extensive comments, thus it will be quite good for people like me - old timer hobbyist ;)