Accumulation buffer and FBO

It’s my understanding that FBOs don’t support accumulation buffers. If that’s correct, why? Is it that there isn’t much demand for an accumulation buffer, or are there straightforward ways to accomplish all the same things without an accumulation buffer?

The reason I’m thinking about using an accumulation buffer is to add the contributions of multiple lighting passes. I’m currently doing that using additive blending, but I’m also using blend mode for transparency, and the two uses of blending sometimes interfere with each other.

If that’s correct, why?

We have shaders now.

Order your blending operations.
First, draw the object’s mesh into the depth buffer (with small offset).
Next, apply each light contribution (with Additive blending) with disabled depth writing and enabled depth check.
After that you are free to blend any transparent surfaces on top.

IMO, it’s not so much the shaders, but the render target formats available now.

One of the things accumulation buffers give/gave you at the time is very high precision blending, higher than afforded by the render targets available at the time (RGBA8). They provide 16 bits/channel, for a total of 64 bits! Whereas a standard RGBA8 render target is only 32-bits.

Now we have render targets with 16-bit fixed point, 16-bit floating point, 32-bit floating point, R11F_G11F_B10F packed float, etcetc. which support blending (and MSAA incidentally).

So suddenly the magic “accumulation buffer” isn’t so useful anymore. You want one? Go create one yourself!

For a 1280x1024 system FB, the accumulation buffer is a whopping 10MB! While glxinfo reveals no visuals which don’t have an accumulation buffer, I hope the GPU vendors honor the requested FB config attribs and don’t even waste the memory allocating one of these unless you actually try to use it.

I don’t see how that’s going to work. Transparent surfaces both reflect and transmit light (unless the alpha is 0, in which case there is nothing to render) so you can’t render them without consideration of lighting. And then there’s the issue of how to deal with specular highlights.

Hmm. And how would I simulate glAccum( GL_ACCUM, value )? Something involving rendering a textured quad?

  1. if you need diffuse & specular on transparent surfaces, you can draw them with depth-write AFTER all opaque objects are drawn. The transparent objects has to be drawn in order from distant to closest.


Hmm. And how would I simulate glAccum( GL_ACCUM, value )? Something involving rendering a textured quad?

I guess you just need to draw into a full-screen buffer with constant alpha blending enabled.

If I need diffuse & specular? What else would I do with transparent surfaces? I suppose one could turn off lighting and just use the color of the material, but I don’t know why you’d want to. That’s not how transparent objects work in the real world. If you’re looking at a glass and then turn off all the lights, you don’t see the glass any more.

I still need multiple lighting passes for the transparent stuff as well as for the opaque stuff. If I made the transparent surfaces write to the depth buffer, then I’d only be able to render the frontmost surface, except for the first lighting pass.

I am aware of the need to sort transparent surfaces by depth, but that doesn’t solve my problems.

Perhaps it will help to consider a simplified example. Suppose we have an nearly-opaque object with color A, and in front of that there is a transparent object with color B. (I assume that the rear object is nearly opaque so that it will be handled like other transparent objects, but we need not worry too much about what is behind it.) Suppose that two light sources contribute brightnesses L and M. If we can do this all in one pass, and we assume premultiplied alpha, the resulting color value ought to be B*(L+M) + (1-alpha)A(L+M). But now suppose that for some reason we must handle the lights in separate passes. The first pass produces BL + (1-alpha)AL. In the second pass, if we are to use blending, what is the blend function? If we were doing multiple lighting passes on opaque objects, we would use glBlendFunc( GL_ONE, GL_ONE ). If we use that blend function in this case, we add BM + AM, resulting in a total of B(L+M) + (1-alpha)AL + A*M, which has too much contribution from A. You can similarly check that glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ) gives an incorrect result.

If I need diffuse & specular? What else would I do with transparent surfaces? I suppose one could turn off lighting and just use the color of the material, but I don’t know why you’d want to. That’s not how transparent objects work in the real world. If you’re looking at a glass and then turn off all the lights, you don’t see the glass any more.

You know, CG is always a fake.

As for your problem: you can have a separate buffer to accumulate lighting for transparent surfaces (with Additive blend) and then apply it to the main buffer using required blend function.

Certainly, but I want the best fake I can make.

It is not possible to separate the blending like that (unless I misunderstand what you wrote). Even if you consider only the transparent surfaces, you cannot get the right result using only additive blending. It is necessary to use alpha blending when painting each transparent surface onto the deeper ones, but it is necessary to use additive blending when adding lighting passes.

I see that I wasn’t explicit about what I thought of doing with an accumulation buffer, so I may as well do that now:


clear the accumulation buffer
for each lighting pass i = 1, 2, ... n
    clear the color buffer
    render opaque stuff with light i
    render transparent stuff, far to near, with light i (alpha blending)
    glAccum( GL_ACCUM, 1.0 )
glAccum( GL_RETURN, 1.0/n )

It’s easy to achieve the code functionality you posted:


define buf-0, buf-1 - RGBA textures, attach both + depth buffer to an active FBO.
select buf-0
clear color
for each light:
   select buf-1
   clear color & depth
   render opaque stuff with light i
   render transparent stuff, far to near, with light i (alpha blending)
   select buf-0
   set blend 1,1
   draw size-1 quad with texture buf-1
select buf-0
set constant alpha = 1/n
set blend constant alpha,0
draw size-1 quad with texture buf-1

Thanks a lot! It took a while to get here, but I think this is what I was asking for in my first post. (Come to think of it, I guess I shouldn’t have had that 1/n in there. Some part of my brain was thinking of an average rather than a sum.)

I’m glad to help you, finally :slight_smile:

As you can see, the accumulation buffer can be set up easily. Moreover, manual control over render targets and blending functions gives you more freedom.

This constant alpha/color blending can be quite handy. I used it for HDR light successfully for the first time.