FBO with depth and 3 RGBA16F as output - issues

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);
}

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).

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?

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?

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
");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
		printf("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
		printf("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
		printf("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
		printf("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
");
		break;
	case GL_FRAMEBUFFER_UNSUPPORTED:
		printf("GL_FRAMEBUFFER_UNSUPPORTED
");
		break;
	default:
		printf("Unknown FBO error
");
		break;
}

for(int i = 0; i < int(_tex_id.size()); i++)
{
	printf("FBO attachment ID: %d
", i);
	switch(_buffers[i])
	{
	case GL_COLOR_ATTACHMENT0:
		printf("FBO attachment point: GL_COLOR_ATTACHMENT0
");
		break;
	case GL_COLOR_ATTACHMENT1:
		printf("FBO attachment point: GL_COLOR_ATTACHMENT1
");
		break;
	case GL_COLOR_ATTACHMENT2:
		printf("FBO attachment point: GL_COLOR_ATTACHMENT2
");
		break;
	(...)
	case GL_DEPTH_ATTACHMENT:
		printf("FBO attachment point: GL_DEPTH_ATTACHMENT
");
		break;
	case GL_STENCIL_ATTACHMENT:
		printf("FBO attachment point: GL_STENCIL_ATTACHMENT
");
		break;
	default:
		printf("Unknown FBO attachment point
");
		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.

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.

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 :stuck_out_tongue: 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 :wink: