MRTs

I am absolutely running out of time and I’m hoping I can get a clear answer from here.

I need MRTs for a project. I successfully used FBOs before but never with multiple render targets. My test structure is this:

1 FBO (call it A)
Attach A four textures at Attachments 0,1,2 and 3
Each of the four textures are at texture levels 0, 1, 2, 3 (GL_TEXTUREi)
I output to those textures in frag shader as this:

fragOutput0 = vec4( 1.0, 0.0, 0.0, 1.0 );
fragOutput1 = vec4( 1.0, 1.0, 1.0, 1.0 );
fragOutput2 = vec4( 1.0, 1.0, 1.0, 1.0 );
fragOutput3 = vec4( 1.0, 1.0, 1.0, 1.0 );

Each of these fragOutputs are bound to 0,1,2,3 during linking stage of the shader.

Then I feed in these four textures into a new frag shader pass. I initialize the texture sampler positions at 0,1,2,3. At every frame before I initialize the second shader I bound these four textures to the four texture locations (GL_TEXTUREi) just in case.

And I draw the output of the second frag shader on screen.

The output is just one-to-one copy of the texture. I basically output whatever is in each of the textures and the problem is that they all have the same thing! (RED color as I output to out location 0 in first shader). It’s almost like I’ve bound all of them to the attachment0 location but I haven’t, they are all different, they are all different textures, attached to the different attachment places in the FBO and I assume they should be outputted as the first texture red and the rest all black. But all of them are red.

I have no idea why. Help?

Thanks.

Here is how I initialize 2 of the 4 textures and pass them to the second shader. shaderSelectionMaskPass_ is the second shader.


glGenFramebuffersEXT( 1, &fboRaycastingPass_ );
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboRaycastingPass_);

	//Create color output texture
	glActiveTexture( GL_TEXTURE0 );
	glGenTextures(1, &colorOutputTex_);
	glBindTexture(GL_TEXTURE_2D, colorOutputTex_);
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, SCREEN_W, SCREEN_H,
		0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
	glGenerateMipmapEXT(GL_TEXTURE_2D);

	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
		colorOutputTex_, 0 );
	loc = glGetUniformLocation( shaderSelectionMaskPass_, "colorcolor" ); glUniform1i( loc, 0 );

	//Create node list textures 1
	glActiveTexture( GL_TEXTURE1 );
	glGenTextures(1, &nodeListTex1_);
	glBindTexture(GL_TEXTURE_2D, nodeListTex1_);
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, SCREEN_W, SCREEN_H,
		0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
	glGenerateMipmapEXT(GL_TEXTURE_2D);
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D,
		nodeListTex1_, 0 );
	loc = glGetUniformLocation( shaderSelectionMaskPass_, "nodeList0" ); glUniform1i( loc, 1 );

I do this before both the first shader pass and the second shader pass (They both output to four textures):


GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT };
glDrawBuffers( 4, buffers );

And my second shader which outpus textures look like this:


uniform sampler2D colorcolor;
uniform sampler2D nodeList0;
uniform sampler2D nodeList1;
uniform sampler2D nodeList2;

in vec3 vertexPos;

out vec4  fragOutput0;
out vec4 fragOutput1;
out vec4 fragOutput2;
out vec4 fragOutput3;

void main( void )
{	
fragOutput0 = vec4( texelFetch( nodeList0, ivec2( int(vertexPos.x), int(vertexPos.y) ), 0 ) );
fragOutput1 = uvec4( 0.0, 0.0, 0.0, 0.0 );
fragOutput2 = uvec4( 0.0, 0.0, 0.0, 0.0 );
fragOutput3 = uvec4( 0.0, 0.0, 0.0, 0.0 );
}

Someone might spot your error. However it’s usually easier to get replies if you know where the issue is.

In order to determine the location of the problem I would start with determining if the output from the first renderer is ok. That is I would render 4 quads, each with one of the textures from the first shader. Obviously I’d change the shader to give different output for the 4 textures :slight_smile:

If that went well, then the problem is feeding it to the second shader. In that case I would start by writing a simpler 2nd shader which accepts only one texture and has only one output. I’d then try two inputs and still one output. If that works I’d try going for two outputs.

This way you should be able to narrow down where it all breaks down.

You are right, my bad. The rush kind of took over.
Yes I tested out the outputs from the first shader and they are all correct. So in fact it may not be about multiple render targets as I seem to get the right textures at each stage.

But the problem is in the second shader, all 4 input samplers point to stage 0 (which they should point 0,1,2,3 respectively).

The last code I posted has the second shader. You can see above in the code before that, that I initialize the texture locations accordingly. Here is again how I do it:


//Some code...
loc = glGetUniformLocation( shaderSelectionMaskPass_, "colorcolor" ); glUniform1i( loc, 0 );
//Some code...
loc = glGetUniformLocation( shaderSelectionMaskPass_, "nodeList0" ); glUniform1i( loc, 1 );
//Some code...
loc = glGetUniformLocation( shaderSelectionMaskPass_, "nodeList1" ); glUniform1i( loc, 2 );
//Some code...
loc = glGetUniformLocation( shaderSelectionMaskPass_, "nodeList2" ); glUniform1i( loc, 3 );
//Some code...

But still all 4 samplers point to zeroth stage and so whatever I fetch in them is the contents of the texture bound to GL_TEXTURE0.

I tried it with only one output texture for shader 2, rendering directly to screen for again second shader instead of rendering to a target and drawing it, no luck.

well i can see several problems

basically setting up the FBO is the easy part


glBindTexture(GL_TEXTURE_2D, color1_tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, 800, 600, 0,GL_RGBA, GL_FLOAT, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, color1_tex, 0);


glBindTexture(GL_TEXTURE_2D, color2_tex);	
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, 800, 600, 0, GL_RGBA, GL_FLOAT, NULL );
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT1_EXT,GL_TEXTURE_2D, color2_tex, 0);

And so on, i am omitting code here but you get the idea.

then before rendering bind the framebuffer
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

and make sure to call
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffersARB(2,buffers);

that should get you in MRT mode

Now i haven’t run this on glsl 1.4 or 1.5 but in glsl 1.2 it’s

gl_FragData[0] = vec4(1.0,0.0,0.0,0.0);
gl_FragData[1] = vec4(1.0,0.0,0.0,0.0);

so my guess would be that it’s something like

out vec4 fragOutput[];

fragOutput[0] = uvec4( 0.0, 0.0, 0.0, 0.0 );
fragOutput[1] = uvec4( 0.0, 0.0, 0.0, 0.0 );

I hope some of this helps.

Are you certain that glGetUniformLocation() is successful and returns a valid location? Your problems could indicate that it does not.

@zeoverlord: I already found out that I don’t have problems with rendering into MRTs. And I don’t see how your code is different than mine.

And yeah it returns valid locations and -1 for the ones not being used.

Here is the code I use to do the second pass (the one that just outputs texture):


void 
Game::_renderSelectionMaskPass()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0_);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glUseProgram( shaderSelectionMaskPass_ );

glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, colorOutputTex_ );
glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, nodeListTex1_ );
glActiveTexture( GL_TEXTURE2 );
glBindTexture( GL_TEXTURE_2D, nodeListTex2_ );
glActiveTexture( GL_TEXTURE3 );
glBindTexture( GL_TEXTURE_2D, nodeListTex3_ );

//Change projection matrix...

glDisable( GL_TEXTURE_3D );
	
//Draw full screen quad and pop matrix...

glEnable( GL_TEXTURE_3D );

Sometimes you have to be stupid and learn from your mistakes.
And sometimes maybe its just too late to be working.

I was setting the texture locations without binding the shader program first.

Someone once said the more mistakes one makes the wiser one gets.

If there’s any truth to this then I’m a genius (or an idiot savant).