OpenGL Blending for 2D Light Effects

Hi, I'm working on a 2D side scroller in OpenGL, and I'm trying to implement simple 2D light effects.

I draw the scene using a series of texture mapped quads (textures have alpha channels for masking and transparency effects). The problem is I'm having a hell of a time wrapping my brain around blending, and I've had a trouble finding any information that gives some good, visual examples of what different blending combinations accomplish.

Right now I'm using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), which is working fine for alpha blending sprites drawn in layers (using the z buffer in an orthogonal viewport for layering).

I had the idea of making an area appear dark simply by drawing a quad that fills the entire viewport, with a certain color (usually black) and with a variable alpha depending on how dark I want the scene to be.

Next, I drew a number of 'lightmaps' in photoshop, essentially just transparent pngs with a diffuse white blob in the middle, acting as a circular light. In this way, I can just use color4f() to create a wide range of fake lights.

Now, I'd like to draw this on a quad and blend it such that it negates the effect of the large black quad where the texture is opaque, and do nothing where the texture is transparent, but I am not really sure how to go about this. I could try brute force with the blending function, but I'd much rather have some sort of understanding on what is going on. Additionally, is this even the preferred/fastest way of doing this? I got the idea from 3D lightmaps using multitexturing, but I have no idea if this is particularly efficient.

You should read chapter 6 of the Red Book very carefully. I know it's kind of hard to pick up at first, but if you actually study it and do some further Googling if necessary it will save you loads and loads of guess-work. I still don't fully understand the relationships all the time, but at least it finally gave me a clue about what's going on, and why only a small handful of combinations are useful for most purposes. Most importantly, now I can figure out precisely why a particular combination is doing/not doing what I want, if necessary.

Also, write a function to cycle through all the blend modes as you click a button or press a key (or whatever, like have a couple pop-up menus instead), so you can actually see the results of a given combination. Then when you find the visual effect you're looking for, go back and work out the blend function, using the information in ch. 6, by hand to figure out why it's doing what you want.

I think what I might do on the iPhone is render the lightmap to the alpha channel and blend a quad over the top with that if you just want single color lights. If you want multi-color lights, you could either render it to the frame buffer before rendering the scene and then multiply the rest of your stuff on top of that drawing front to back. (can't use alpha blended sprites this way) You could also render the lightmap to a texture and then blend that on top of the scene if you want alpha blended sprites.

If it's just going to be a static lightmap, just pre-render it to a texture that you stretch over the entire level.

OK, so after some reading (I had no idea that the entire Red Book was online for free, thanks for that) and some experimentation, I'm pretty sure I'm going about this the entirely wrong way.

In a nutshell, I'm placing an untextured semi-transparent quad over the entire view, making it darker, and I want to selectively poke a variable amount of holes in it's alpha using a soft blob gradient for the alpha. I suppose I could just retexture the quad with new texture coordinates every frame, but that seems really inefficient (or not?).

I just feel like there is a better way to darken a bunch of 2D texture mapped quads and selectively lighten them with multiple spotlights.

Hard to say exactly, without a mockup (pic) of what exactly you're trying to do (even then it might be hard to say), since I can't fully envision it. Skorche's idea sounds pretty good.

I had a situation where I had dimmed sprites in the background by lowering their luminosity (like glColor4f(lum * r, lum *g, lum * b, 1.0f)), and had spotlights over it by tweaking the blend mode, which looked great for the situation. I was using premultiplied alpha textures, like you'd normally get from Texture2D or straight from CoreGraphics on iPhone, and I believe the blend mode I created for it was "overlay" for the spotlights. The blendfunc I used for the lights was GL_DST_COLOR, GL_ONE.

Like I mentioned earlier, the way I actually discovered that this particular blend mode would work for my situation, was by cycling through *all* of the available blend modes. Instead of guessing, it took only a few minutes of key pressing to get my effect.

BTW, the "untextured semi-transparent quad over the entire view, making it darker" technique is a perfectly acceptable way of dimming things. It might not be usable for the blend mode trick, but otherwise I use it all the time for things like fading out the entire scene.

Hmm, giving each object a luminosity constant is a good idea, I'll try that and then try maybe glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA), I think that should give the effect I'm going for with how I have my textures setup.

Of course, I can still use the giant quad for no holds-barred scene transitions etc.

I'll post some screen shots and the code if I'm successful just in case anyone else is trying something similar on these forums. Thanks for the help, AnotherJake!

OK, it took longer than I thought, but I've come up with a solution, albeit a less-than-optimal one.

The whole blending thing clicked finally after thinking about it for so long. I went back to using a black semi-transparent quad to dim the scene.

Now, if I'm understanding the equation right, with a texture that has 1.0 alpha in the center over something using glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA), doing this: (current color * texture's color + current color * texture's alpha). As the texture is white with a variable alpha, it effectively just amplifies the color already there by a factor of two at the brightest part.

So if I dim the scene using a quad with 0.5 alpha, I'm effectively halving all the colors in the scene, but I can negate this by doubling them again. It looks like this, which is what I'm going for:

Now, if I want to dim it more, say I set the quad's alpha to .75 (quartering all colors in the scene), I can blend 1 instance of this light quad over to double the colors, boosting them back up to half, then blend another instance of the light quad over that to boost them back up to their original values. It looks like this:

Also, here is the png I'm using for the light texture (don't expect to see anything in your browser though!): Light Texture

Anyway, this solution doesn't seem particularly elegant. I can mix and match various dimming/brightness values by varying the number and alphas of the light map quads, but as you can see in the second screenshot, each additional use of the light quad amplifies artifacts in the alpha channel itself. I do feel I am getting closer though.

NelsonMandella Wrote:Dynamic lighting would be easier and is way more flexible.

I'm not even quite sure what that is. Do you mean using OpenGL's built in lighting functions? I've been trying to avoid those since it's all on a per-vertex basis, I don't think it would work very well for a bunch of texture mapped quads.

No I'm talking about doing your own lighting calculations. The way you would do lighting is to subdivide your quads into smaller quads and light their vertices. Say you're using 64x64 quads, well you can achieve totally smooth lighting by subdividing the quad into 16(4x4) smaller quads and lighting vertices. And you only need to calculate lighting for subdivided quads which fall within the sphere of a light.