PDA

View Full Version : Multi-pass rendering problem



LUXO99
11-10-2014, 04:45 PM
Hi,
I'm having problems with multi-pass rendering... I guess I'm forgetting some command or I'm just putting the opengl calls in wrong order, but I couldn't get my model in the screen.
Ok, I'm trying multi-pass render for lights, so I'm making a first pass to fill the depth buffer, after I paint the ambient, and finally I blend the lights... but it doesn't work.
Here you have a pseudo-code of my program.

First pass, framebuffer with depth buffer:

glBindFramebuffer(GL_FRAMEBUFFER, multirender_fbo_);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glClearColor(0.f, 0.f, 0.25f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(ambient_program);

DrawScene();

Second pass, ambient color:

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(0.f, 0.f, 0.25f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);

DrawScene();

Third pass, lights:

glDepthMask(GL_FALSE);
glDepthFunc(GL_EQUAL);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

glUseProgram(light_program_);

DrawScene();

This only paints the color of glClear()... anything more.

I try to make different things, as create a renderBuffer color inside the frameBuffer, paint the color in the first step, copy the framebuffer into the screen with glBlitFrameBuffer and try
to blend the lights... doesn't work neither. Also, I tried to paint the ambient color using the configuration of the third pass, enabling blend and using GL_EQUAL etc... but doesn't paint
anything neither... I tried different configurations, and only "works" (because doesn't work properly) if I comment in the third pass all the functions related with the frameBuffer...
The problem is that configuration paint me everything transparent...

So if anyone can help me, I will appreciate! Thank you very much!

Dark Photon
11-11-2014, 10:39 AM
Did you check for GL errors (glGetError() or use a debug context with a GL event callback).

LUXO99
11-11-2014, 03:45 PM
Did you check for GL errors (glGetError() or use a debug context with a GL event callback).

No I didn't. I used GDebugger and NVIDIA insight to see if the data and the buffers were loaded correctly and they are, but I can try with glGetError() to see if this give some more info. Thank you!
I'll put my results to show what happened.

Dark Photon
11-12-2014, 05:45 AM
Well, the basic template for what you're doing looks good.

However looking back, one thing I just noticed that I didn't see before is that when you finish rendering depth and switch to color, you are flipping FBOs (specifically, reverting to the system FB). Why? You're going to be depth testing against the depth buffer in your FBO, not the one on your system framebuffer.

I would get rid of the bind of framebuffer 0 before rendering your color passes and retry. Then your depth tests will be against the depth buffer you rendered previously.

LUXO99
11-12-2014, 11:26 AM
Well, the basic template for what you're doing looks good.

However looking back, one thing I just noticed that I didn't see before is that when you finish rendering depth and switch to color, you are flipping FBOs (specifically, reverting to the system FB). Why? You're going to be depth testing against the depth buffer in your FBO, not the one on your system framebuffer.

I would get rid of the bind of framebuffer 0 before rendering your color passes and retry. Then your depth tests will be against the depth buffer you rendered previously.

Hi Dark!
I made changes, and now is working... but I'm still having a doubt.... It's working with this config set:

1 pass:
Same as before

2 pass:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(0.0f, 0.0f, 0.25f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

DrawScene();

3 pass:
glDepthMask(GL_FALSE);
glDepthFunc(GL_EQUAL);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

glUseProgam(light_program);

DrawScene();

My doubt is because if I don't clear the depth buffer in the second pass, it doesn't work. So, if I'm calculating the depth in the first pass, and clearing in the second pass, which depth buffer is using to make the depth functions?!?! Unless in the second pass I was clearing the depth of the framebuffer of the screen, and not the previous framebuffer depth... In this case (if it's possible) How does it know that it has to use the first depth buffer to make the calculations?!?!

Thank you Dark!

Dark Photon
11-12-2014, 04:41 PM
Hi Dark!
I made changes, and now is working... but I'm still having a doubt.... It's working with this config set:

1 pass:
Same as before

2 pass:
glBindFramebuffer(GL_FRAMEBUFFER, 0); <--------------------------------------
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(0.0f, 0.0f, 0.25f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

DrawScene();

3 pass:
glDepthMask(GL_FALSE);
glDepthFunc(GL_EQUAL);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

glUseProgam(light_program);

DrawScene();

You didn't make the change I suggested. Notice that your 2nd pass still is flipping which framebuffer is active from your FBO (that you rendered depth into) to the system framebuffer.


My doubt is because if I don't clear the depth buffer in the second pass, it doesn't work.

That's because by binding the system framebuffer at the top of pass 2 (rather than just using your off-screen FBO that you bound in pass 1), your not using the results of pass 1 at all, making it useless. So for pass 2 to populate the depth buffer correctly, you have to clear it and render color+depth to it in pass 2 (which is what you are doing now).


So, if I'm calculating the depth in the first pass, and clearing in the second pass, which depth buffer is using to make the depth functions?!?!

Because of your BindFramebuffer(0) at the top of pass 2, your pass 1 FBO (and its depth buffer) is not being used. So the 2nd pass is populating the color+depth buffer in the system FBO (framebuffer 0).

Decide whether you want to use this technique in your off-screen FBO or the system FB. Then bind the one you choose before pass 1, and don't do any BindFramebuffer calls after that.

Also if your ambient pass is pretty cheap, consider just applying that in the same pass that you seed the depth buffer. If not, keep it separate.

LUXO99
11-13-2014, 08:23 AM
You didn't make the change I suggested. Notice that your 2nd pass still is flipping which framebuffer is active from your FBO (that you rendered depth into) to the system framebuffer.



That's because by binding the system framebuffer at the top of pass 2 (rather than just using your off-screen FBO that you bound in pass 1), your not using the results of pass 1 at all, making it useless. So for pass 2 to populate the depth buffer correctly, you have to clear it and render color+depth to it in pass 2 (which is what you are doing now).



Because of your BindFramebuffer(0) at the top of pass 2, your pass 1 FBO (and its depth buffer) is not being used. So the 2nd pass is populating the color+depth buffer in the system FBO (framebuffer 0).

Decide whether you want to use this technique in your off-screen FBO or the system FB. Then bind the one you choose before pass 1, and don't do any BindFramebuffer calls after that.

Also if your ambient pass is pretty cheap, consider just applying that in the same pass that you seed the depth buffer. If not, keep it separate.

Hi again Dark,
I tried to make the change you proposed... by that gave me more doubts... because if I switch the frameBuffer to the screen buffer later.... then I have to create a renderBuffer for color in my framebuffer, then render the scene, switch to screen, copy this renderBuffer and make the blend?!?! or make everything in my frameBuffer and then switch to the screen and make a copy (that seems better than the first thought)...
I think OpenGL is getting confused in my brain with multi-pass... I mean, I think I understand where and why I'm using the different fragment OPs, but is the use of different frameBuffers what confuses me...

Man thank you for your patience and wisdom!

Dark Photon
11-13-2014, 05:18 PM
Hi again Dark,
I tried to make the change you proposed... by that gave me more doubts... because if I switch the frameBuffer to the screen buffer later.... then I have to create a renderBuffer for color in my framebuffer, then render the scene, switch to screen, copy this renderBuffer and make the blend?!?! or make everything in my frameBuffer and then switch to the screen and make a copy (that seems better than the first thought)...
I think OpenGL is getting confused in my brain with multi-pass... I mean, I think I understand where and why I'm using the different fragment OPs, but is the use of different frameBuffers what confuses me...

It's the use of two different framebuffers in your pseudocode that's confusing me too! I think pretty close to on the same page. Why not either:

1) Do what you said and I was trying to say, and "...make everything in my frameBuffer and then switch to the screen and make a copy [to the system framebuffer] (that seems better than the first thought)", OR
2) Just do everything in the system framebuffer (and then there's no copy to the system framebuffer required).

Here's what I was trying to say for #1:


// ----- First pass, framebuffer with depth buffer: -----

glBindFramebuffer(GL_FRAMEBUFFER, multirender_fbo_);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

// COMMENTED OUT:
//glClearColor(0.f, 0.f, 0.25f, 0.f);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// ADDED:
glClear(GL_DEPTH_BUFFER_BIT);

glUseProgram(ambient_program);

DrawScene();

// ----- Second pass, ambient color: -----

// COMMENTED OUT:
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
// ADDED:
glDepthMask(GL_FALSE);
glDepthFunc(GL_EQUAL);

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(0.f, 0.f, 0.25f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);

DrawScene();

// ----- Third pass, lights: -----

// COMMENTED OUT - This was already done above:
//glDepthMask(GL_FALSE);
//glDepthFunc(GL_EQUAL);

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

glUseProgram(light_program_);

DrawScene();

// Finally do what you want with the FBO (multirender_fbo_) contents, such as
// Blit the color buffer to the system framebuffer.


Or if you wanted to do #2, just change the glBindFramebuffer to bind FB #0, and then everything else is the same (except of course don't blit to the system FB in at the end).