glBlendFunc(GL_DST_ALPHA, GL_ONE) behaving unexpectedly

I’m doing a bit of additive lighting for a game and rendering each light pass by drawing its attenuation and radius into the alpha buffer, and then drawing the bump map in the second pass using glBlendFunc(GL_DST_ALPHA, GL_ONE).

Now to my mind there’s no way that I could clobber the existing background when I’ve got a dst parameter of GL_ONE, but that’s exactly what’s happening. It is in fact no different to rendering with glBlendFunc(GL_DST_ALPHA, GL_ZERO) - the second light clobbers what’s under the first instead of adding its contribution to the framebuffer. I’ve tested this with much simpler rendering - drawing just flat triangles instead of a bump map, and it’s still doing it. I also, for an experiment, tried glBlendFunc(GL_ZERO, GL_ONE) which to my mind is a no-op on the colour buffer, yet it still draws something.

Am I getting confused or are Geforce cards incapable of performing this blend?

Here’s a screenie of it not working.

Cas

I hope this isn’t too obvious, but are you sure you’re not overwriting the destination alpha with your first pass? You have to use glColorMask() to disable writes to the destination alpha.

– Tom

Obvious #2:
You also need to glEnable(GL_BLEND);

Don’t slap me, I just want to make sure

Don’t worry, blending is enabled.

The algorithm goes:

  1. Draw ambient pass with no blending.

  2. For each light:

2a. Draw attenuation map using alpha textures using glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE) and blending disabled, i.e clobber the alpha buffer because I’m not interested in its contents from one light to the next

2b. Draw bump map blended using glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) and glBlendFunc(GL_DST_ALPHA, GL_ONE), which should give me an attenuated bump map which is added to whatever is already in the colour buffer. Additive blending is especially important because the ambient pass was drawn beforehand.

2c. Go to next light.

  1. Draw diffuse pass using glBlendFunc(GL_DST_COLOR, GL_ZERO)

Which all works lovely for one light.

Maybe [this screenshot](http://www.shavenpuppy.com/xap/screenies/stillbroken.jpg\) will help you diagnose it for me Notice the overlap in the top right where the small light has been drawn on top of the large light. See that square corner showing through? That’s part of the bump map on the previous light :stuck_out_tongue: Yet you can see how it’s clobbered the previous light (just) in the bottom left corner of the second light.

Cas

[This message has been edited by cix>foo (edited 02-20-2003).]

[This message has been edited by cix>foo (edited 02-20-2003).]

Hmm I do my lighting in almost an identical way to what you just outlined for your steps, and it runs fine on all hardware that its been tested on (GF2, GF2mx, GF3, GF4mx, GF4ti, Radeon8500, Radeon9500, Radeon9700), though different hardware uses different paths (Radeon8500 and above do it all in a single pass, gf3/4ti do it in 2 passes, gf2 and below do it in 3 passes).

If anything, I had troubles with this on ATI hardware. I submitted a bug report on it, they denied that there was any bug, and the next driver release (which was the very next day infact) fixed the bug.

What drivers are you running?

It’s not immediately obvious to me what’s going wrong – I’m not aware of any NVIDIA driver problems that would explain this problem. The images didn’t help that much, but I didn’t examine them in great detail.

One other “obvious” thing to check: Make sure you are actually getting a pixel format with alpha planes. NVIDIA provides pixel formats with and without alpha. To check in your app:

glGetInteger(GL_ALPHA_BITS, &alphaBits);

Alpha blending and alpha test will still “work” without alpha planes. But if you blend with DST_ALPHA or ONE_MINUS_DST_ALPHA, you really end up with ONE or ZERO, respectively.

There’s a lot of alpha blend operations that don’t need alpha planes at all. One example is the standard transparency blend (SRC_ALPHA / ONE_MINUS_SRC_ALPHA).

Standard Dell 8100 Inspiron drivers on this laptop - can’t use anything else because they cause crashes.

The funny thing is it’s working perfectly as expected with one light. It looks very like I’m drawing all of pass 2a. instead of alternating 2a. and 2b. each time but a trace seems to indicate otherwise.

Cas

Fixed it!

A bit more hard thinking solved this problem. The evidence goes something like this: if there’s no way the blending mode couldn’t be working properly, and it works for one light but the next light breaks the first working light then it’s going to be down to the vertex data being overwritten! And this is exactly what was happening. I calculated the lighting texture coordinates in one go before rendering, which meant the second light overwrote the texture coordinates of the first set of triangles and made it look like it was screwing the blending up.

Sorry to bother everyone I’ll crawl back under my keyboard now.

Cas