2D lighting

Started by
13 comments, last by medevilenemy 11 years, 11 months ago
Hi all, so, I've been looking into how to implement better looking lighting in my 2D engine and from what I can tell the most relevant way seems to be to draw a low alpha light textured quad over (well, at the same z position, really) a high alpha blanket (or is it the reverse, this is rather confusing) with the appropriate blending. To test this, I've been playing with drawing the following quads on my screen in various alphas, orders, and with various blending configurations:

glColor4d(1.0, 1.0, 1.0, 0.01);
glBegin(GL_QUADS);
glVertex3d(-1.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, -1.0, 0.0);
glVertex3d(-1.0, -1.0, 0.0);
glEnd();

glColor4d(1.0, 1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex3d(-0.9, 0.0, 0.0);
glVertex3d(0.1, 0.0, 0.0);
glVertex3d(0.1, -1.0, 0.0);
glVertex3d(-0.9, -1.0, 0.0);
glEnd();

I currently have the following at least somewhat relevant config stuff:
glEnable(GL_BLEND); // allows blending (transparency)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // function for blending
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH); // allows smooth shading (gradients)
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0);

I can't seem to find the right configuration for what I'm trying to do. I'm drawing my stage at a z level farther (higher z in my case) and drawing these masks over it. I want to eventually draw a black mask over everything and draw lights to cancel out bits of that mask to light appropriate areas (with an appropriate gradient texture). What am I doing wrong? This has been done innumerable times, but I can't seem to wrap my head around the examples I've seen.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Advertisement
Pretty sure the problem is ultimately that I don't understand what the different blend func configurations do in practical terms, or even if there is one for what I'm trying to accomplish... I'm sure there's a way, I've seen it done.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
It's kind of hard to understand what you're trying to accomplish. If you want more control, simply write your own shader and do precisely what you need.
What i'm going for is something sort of like
but without the shadows. Basically, I want the stage to be dark, and by placing a light on it I could illuminate a circular area with an appropriate gradient, thereby making things in the illuminated area visible (or more visible). These lights could, hypothetically, be moved. I suppose this can sort of be described as having an opaque blanket over the stage, through which gradient holes are punched in certain places to reveal the things beneath.

I don't know the first thing about shaders... everything I do is in the fixed pipeline (horribly outdated, I know). (sidenote: If anyone knows of a way to update the opengl libraries available to mingw, that would be awesome. I know microsoft doesn't provide drivers for newer versions of opengl with windows, but the card manufacturers do, so I'd figure the libraries would be available... alternatively I suppose something like glew would give access to newer features, but I can't seem to get glew to work with mingw/Code::Blocks)
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.

Pretty sure the problem is ultimately that I don't understand what the different blend func configurations do in practical terms, or even if there is one for what I'm trying to accomplish... I'm sure there's a way, I've seen it done.


In practical terms:

  • At time of blending you have 2 colours, destination and source. Destination being what is already drawn to that pixel, and Source being the colour you are currently drawing. (in some circumstances you can also have an additional constant-colour, but I'm not sure if that exists in OpenGL)
  • There are multiple blending equations (glBlendEquation). The default is Add, which is SrcResult + DstResult, there is also Subtract, Multiply, Min and Max.
  • SrcResult and DstResult come from using the functions specified in glBlendFunc to operate on Source and Destination.
  • GL_ZERO: 0 * value // i.e. use zero
  • GL_ONE: 1 * value // i.e. use value directly
  • GL_SRC_ALPHA: Source.a * value // i.e. multiply the colour by the alpha of source (regardless of if value is Destination or Source)
  • GL_DST_ALPHA: Destination.a * value // i.e. multiply the colour by the alpha of destination (regardless of if value is Destination or Source)
  • GL_ONE_MINUS_SRC_ALPHA: (1.0f - Source.a) * value; // the inverse of GL_SRC_ALPHA, mutiply by the remainding fraction of sources' alpha
  • GL_ONE_MINUS_DST_ALPHA: (1.0f - Destination.a) * value; // same as above, except using the remainder of destinations' alpha.

    Using the default blending example of Add, with SrcAlpha, InvSrcAlpha, what you have is a linear-interpolation from the destiation to the source by sources alpha:

    ResultingPixel = (Source.a * Source.rgba) + ((1 - Source.a) * Destination.rgba

    Note that through extensions or OpenGL2+ you can also seperate the alpha channel to use a seperate equation.
Thanks, that does help clarify some stuf, though I'm still not really sure what the proper equation for my purpose is... I don't really care abou the color, its mostly that I want the equivalent of subtracting the alpha of the source (if I understand the terminology properly) form the alpha of the destination to get the final alpha. Additional potential complication: This could very well mess up how the sprites and whatnot underneath blend... At the moment they look just fine with glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), but clearly that isn't the right setting for what I'm trying to do here... I don't suppose there's a way to set different blending funcs for different z depths.

At this point I suppose there are two things I need to know/figure out:
1) How to achieve the desired effect
2) How to prevent (1) from interfering with the underlying scene.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
As far as 2) is concerned, it comes down to order of draw calls. You can freely change blend functions and equations in between draw calls, just like anything else on the video card.
So if you draw your background, then your lighting filters, then your sprites you should be fine (Noting that your sprites blending requirements are source, not destination, so whatever has already been put into alpha is irrelevant).
Hmm. In my object system, lights are technically classified as scenery objects, thus I can't strictly order them to the back. What I may do is split them out into a separate category (logically to be called [s]walrus[/s] lights), which I can then put at the end of my update stage. This way I can combine the overlay "blanket" and hole punches into one big step. Thanks for the idea!

Now all that remains is (1) as described above.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Any suggestions? Help is greatly appreciated.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Been experimenting some more, without any luck. It seems no matter what I do, I just end up with a white box on the screen.

I'm now isolating the experimental code by drawing it last, with glpush/pop matrix, and drawing the following:

glColor4d(1.0, 1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex3d(-1.0, 0.0, 0.01);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, -1.0, 0.0);
glVertex3d(-1.0, -1.0, 0.0);
glEnd();

glColor4d(1.0, 1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex3d(-1.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, -1.0, 0.0);
glVertex3d(-1.0, -1.0, 0.0);
glEnd();

What I want to do is have the 2nd quad nullify the first quad (by subtracting the alpha) to reveal the stuff drawn earlier underneath. If I understand correctly, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA should do the trick but no variant I've tried has made a difference.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.

This topic is closed to new replies.

Advertisement