9
\$\begingroup\$

I'm starting out with GLSL and I've implemented simple deferred shading that outputs G-buffer with positions, normals and albedo.

I've also written a simple point light shader.

Now I draw a sphere for the point light and output goes into a lighting buffer.

The problem is, how do I combine the results of lighting buffer when drawing multiple lights?

E.g. when I'm drawing the second light to the lightbuffer using the point light shader, how do I add first light to the second light in the lighting buffer. I mean, you can't read from and write to the same output buffer?

\$\endgroup\$

3 Answers 3

12
\$\begingroup\$

Additive blending, i.e. glBlendFunc(GL_ONE, GL_ONE) and glEnable(GL_BLEND).

\$\endgroup\$
7
  • \$\begingroup\$ does depth testing have to be disabled for this? \$\endgroup\$
    – woojoo666
    Commented May 26, 2015 at 7:53
  • 1
    \$\begingroup\$ @woojoo666 No. In fact it should be enabled with the depth test set to less-equal, so that surfaces that precisely match the previous pass will go through. If the depth test is off, then surfaces will incorrectly accumulate light from whatever's behind them. :) \$\endgroup\$ Commented May 27, 2015 at 17:22
  • \$\begingroup\$ hmm, it seems like thats exactly whats happening though. turning blending on makes front faces blend with back faces, even though I kept depth testing enabled. do I need to do something with the depth mask as well? \$\endgroup\$
    – woojoo666
    Commented May 28, 2015 at 5:42
  • \$\begingroup\$ did a bit more testing, seems like draw order matters (drawing front-to-back makes depth-testing work correctly and blend only happens if faces are equiplanar, back-to-front makes everything blend together). Is there a way to do this without sorting everything? \$\endgroup\$
    – woojoo666
    Commented May 28, 2015 at 15:21
  • 2
    \$\begingroup\$ @woojoo666 Aha, sounds like you solved it on your own. Yes, you have to lay down depth in an opaque pass before you can use any sort of blending. It can be a z-prepass with color writes disabled, or another common way is to do ambient/directional light in a first pass with no blending, then add point/spot lights in later passes with blending. \$\endgroup\$ Commented May 29, 2015 at 18:01
2
\$\begingroup\$

For my deferred renderer, I aggregate all the lights into one light render target using the information from the g-buffer and then sample that render target for light intensity while creating my final backbuffer image.

So basically, I run all my game geometry through my geometry pass to build the g-buffers. From there I feed the g-buffers to my light pass shader. Each light is ran through the pass using a full screen quad. This way my pixel shader can calculate the light intensity for all the visible surfaces from the g-buffer and then add them to the light render target. You simply just add the light intensity for each light to the light buffer but make sure you clamp the intensity from 0 to 1.

All you would need to do to handle different types of lights (point, spotlight, parallel) is to make the light pass more robust by possibly using a constant buffer to designate which lighting procedures to execute.

\$\endgroup\$
4
  • \$\begingroup\$ Yeah, and the question is - how do you add to the light render target? Using alpha blending as Nathan Reed suggested? Because as far as i know you can't read from and write to the same output buffer (which is the light buffer in this case). \$\endgroup\$
    – JBeurer
    Commented Mar 13, 2012 at 0:07
  • \$\begingroup\$ Oops, yeah. I let the output merger handle that with additive blending. When sampling for the final image is when you want to clamp the value to one which works for me as the maximum possible light intensity a surface can receive. From there you can just scale your lights as needed. \$\endgroup\$ Commented Mar 13, 2012 at 19:59
  • \$\begingroup\$ How do you handle cases where a light is behind a wall and should not light up things on the other side of the wall? \$\endgroup\$
    – jjxtra
    Commented Apr 11, 2013 at 19:18
  • \$\begingroup\$ @PsychoDad That's the domain of shadows, which is...a more complicated topic. :) \$\endgroup\$ Commented May 30, 2015 at 23:22
0
\$\begingroup\$

There is likely a better answer than this, but I know, if in your shader you repeat the code needed to do a second light, you can then process two lights on a single object instead of one. It does require droubling up a lot of code for the second light and seams a little redundant, but I know it does work. However, I do believe, as someone will hopefully point out for you, there might be a more elegant solution.

\$\endgroup\$
4
  • \$\begingroup\$ No, that doesn't work that way. I draw a sphere for each point light. Unless the second point light lies withing the sphere of influence of the first light, the second light simply wont be drawn. Your method would work if I draw a fullscreen quad for all the pointlights, however, that is not the correct approach because fullscreen quads are used for global ilumination. Say I have 16 small point lights, that would force me to go through them for each pixel even if the pixel is not lit by it. And usually I'd say each pixel is lit by a one or two lights. And what if i have 100 lights? NO \$\endgroup\$
    – JBeurer
    Commented Mar 12, 2012 at 23:58
  • \$\begingroup\$ The main reason I stated this, is if you are using only two or a few lights, it can help. Especially if you are rending many object, using a blend means you need to redraw the scene for each light, so if you have a a lot of shapes, say one million, or ten million or a billion, each draw costs a lot more to do. Doing it in the shader causes issues if you want lots of lights, but blend causes issues if you want lots of shapes. If you have lots of both, you need to find a middle ground, but usually you have a few lights and lots of objects in games. \$\endgroup\$
    – CodeNeko
    Commented Mar 15, 2012 at 22:27
  • \$\begingroup\$ Nope, deferred shading doesn't work that way. I have to draw the scene only once and store relevant information in G-Buffer. Then a sphere of influence for each light and blend it with the light buffer. And finally combining light buffer with colorbuffer I get the final shaded color buffer. The amount of lighting computations doesn't depend on scene complexity. That is the main advantage of deferred shading in the first place. \$\endgroup\$
    – JBeurer
    Commented Mar 15, 2012 at 22:56
  • \$\begingroup\$ Ah, that make a lot more sense and would considerable better. \$\endgroup\$
    – CodeNeko
    Commented Mar 15, 2012 at 23:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .