2D Lighting Tribulations with Shaders

I tried out the tone mapper a little. I have a small test program to check out my bloom implementation’s looks and performance, and I just plugged it in there. It did look different, but for what I did it didn’t look good. It produced some very unnatural colors when I had high color intensities. I can see why it is perfect for 2D games / sprite graphics, but I don’t really like the style of it, and I wouldn’t ever use this in a 3D game. It would just look weird, kind of like neon lights. A “traditional” tone mapper which reduces color vibrancy apparently looks more like I’d expect it to look in real life.
Bloom seems to work even if used before tone mapping, but the real question is how it looks with dynamic exposure by changing brightMax. I don’t have any good games/tests to try this out on, so I would appreciate if you gave your thoughts on this!

I’m definitely still learning how these shaders work and more importantly how they interact with eachother. I can see why the vibrance would look unnatural, the bottom line is you just typically don’t see it. The sun has to be ridiculously bright to get those kinds of effects, and 2D pictures taken with camera need to have really long exposure times to get the same results.

However for the now and again explosion/fireball/whatever, for a 2D game it will probably look pretty good, and if it doesn’t we’ll change it as we move forward. Shadows are a little wonky right now but that’s almost a separate matter entirely.

Ding ding! Correct answer! xD Just do what feels right and looks good!

Well this epic thread is drawing to a close I suppose. Expect to see Agent D. as an NPC in the final game, who dramatically gives his life to bring power back to your star ship’s lighting system. I’ll probably have a few questions soon about why I still can’t seem to pass (4, 4, 4, 1) to color4f to brighten my sprites even with those settings enabled but I suppose I just need to experiment.

Here’s a pic of bloom as well as shadows, I’ll link to a video soon, pictures don’t really do justice to how awesome dynamic shadows feel.

Both images - a point light moving with the player
First- point light plus yellow light = more bloom
Second- clearer pic of shadows

DAYUM! Looks really awesome! If you have mouse aiming, you could even implement a flash light for him! =D
It’s a little unclear what you mean with “pic of both”. Is the left one the old tone mapper and the right one the luminance based one? IF that’s the case I completely agree that the lighting looks better in the right one. That saturated circle on the left one looks kind of weird, unless there are 2 lights, one small like in the right picture and one large (red one?). Anyway, it’s still frigging awesome!
I’ve been thinking about bloom, and it should be OK to do it before the tone mapping. It’s effects WOULD indeed be affected by maxBright, as it obviously goes through the tone mapping in the end too. Don’t know what I was thinking…

I tried the same formula that we used in the luminance shader, and it looks much better than the basic color / (color+1) one IMO. Before we close this thread for good, I can make a post with all the tone mapping shaders we tried, and some info on their characteristics.

BTW, you should probably implement a non-HDR version of the lighting too. According to Wikipedia, HDR rendering was implemented in hardware in the NVidia Geforce 6 series cards released in 2004 and ATI/AMD Radeon X1300+ cards, released in 2005, so “real” graphics cards shouldn’t be a problem. Heck, most laptops sold today have OpenGL 4 support! The real problem is old integrated Intel cards because of their so-called drivers and their lack of FBO support, let alone HDR support. Later/the latest integrated Intel cards should be better when it comes to drivers, but they still have so bad performance in fill-rate limited stuff (like HDR and 2D lighting/shadows) you’re going to get low, possibly slideshow-like FPS. Depending on what type of gamers you’re targeting your game for, you may not want to exclude a large number of casual gamers with bad/old graphics cards. Personally I would give Intel cards the finger and ignore them, but that might not be a very good idea. ::slight_smile: Just remember that if you actually want to support Intel cards, you’ll have to help all the players who get crashes. Hahaha…

Just go for it! You might even be the first one to have HDR in a 2D sprite-based game! Sorry if I kind of forced it on to you though… xD I will of course help you more if you get stuck somewhere. I may not have much more old code to post past this point, but I’ll still do my best! I’m really interested in this kind of stuff, and I’ve learned a lot too, especially about tone mapping!

Anyway, I’d be honored to be an NPC in your game!

[quote]DAYUM! Looks really awesome! If you have mouse aiming, you could even implement a flash light for him! =D
[/quote]
We actually have cone-shaped lights and the ability to make one follow the mouse from the center of the player, but we’re going to implement something that smooths the edges so it doesn’t look so jagged.

[quote]It’s a little unclear what you mean with “pic of both”. Is the left one the old tone mapper and the right one the luminance based one? IF that’s the case I completely agree that the lighting looks better in the right one.
[/quote]
The left is indeed two lights and I intended for the left example to be a better example of the bloom and the right an example of shadows. Same tone mapping/shaders on both sides.

[quote]BTW, you should probably implement a non-HDR version of the lighting too.
[/quote]
This is the plan, and why we aren’t going to make the mistake of designing a level where the lighting is of paramount importance unless we can accomplish the same gameplay effect with both. This would have been one of the advantages to just using light textures but we’re a lot more flexible this way. I’m not sure how far back intel compatibility goes, but by the time this monster is actually ready I expect a lot more people to have cards that can handle it, even if they’re stock cards.

Regardless it was a good learning experience. We’re about an inch away from getting penumbra working at which point we can finally turn our attention back to other more important aspects. But it’s pretty :smiley: lol

Sounds good. Do post screenshots of your soft shadows later!

Finally fixed the penumbra shader last night/this morning ;D

:o
GIEF SAUCE NAO
(May I see the source code, sir?)

We can probably toss in the shader, seeing as it’s a modified version of a shader we found on a guy’s youtube video that he released to the public.

It finds the angle between the very edge of the umbra where the penumbra starts, and a vector to the current fragment. It then takes this angle as a percentage of the total theta of the penumbra. So if the penumbra is PI/64 radians and the vector from the vertex to the current fragment makes an angle of PI/32 with the start of the penumbra, you end up with a=0.5

Then it uses an “inner and outer intensity” which in our case are 1 and 0 respectively, to weight the a based on defined values. Since we use 1 and 0, you end up with something like:

new_a = (inner - outer) * a + outer

I believe. I don’t have the shader but I can show it when I get back.

It then takes new_a and passes it through the sigmoid function that we use in our lightsource shader as well. This gives the “tapering” effect a non-linear feel. That’s why the penumbra is extremely sharp and contrasts the light heavily near the vertex, but starts to look more blurred as we get further away.

The final_a that results is used via

gl_FragColor = vec4(0, 0, 0, a); 

And we draw the triangle on top of the light texture (prior to blending with the accumulation texture) with:

glBlendFunc(GL2.GL_ZERO, GL2.GL_SRC_ALPHA)

So if we are further away from the umbra, we are blending less black with the light. If we are right up against the umbra, we “clear” pretty much all of the light away, in much the same way that we draw shadows.

Since we got the shader from youtube and modified it more or less, I don’t mind posting it ;D

Do you actually calculate this with angles using trigonometry? Sounds pretty bad performance wise to do in shader… >_< I’d love to see the actual shader code tomorrow though, if that’s okay.
That blend func is awesome! I’m always surprised by what that stupid glBlendFunc can do!

Yes we actually do an acos. Theta = acos( dot(a,b) / normalise(a)*normalise(b) )


varying vec2 pixelPos;
uniform vec2 origin;
uniform vec2 inner;
uniform float angle;
uniform float inner_intensity;
uniform float outer_intensity;

void main()
{
    float a = acos(dot(normalize(pixelPos - origin), normalize(inner))) / angle; //How far along the penumbra are we
    a = (outer_intensity - inner_intensity) * a + inner_intensity; //Obtain a percentage of the intensity
    a = 1.0 / (1.0 + exp(-(a*12.0 - 6.0))); //Sigmoid function
    gl_FragColor = vec4(0, 0, 0, a); //Output the alpha

}

It’s not bad if we keep the number of lights small which we plan to do. We’re not going to have 1000’s of lights and 500 shadow casting geometries, maybe a few lights per screen hanging out behind the scene and the occasional lightsource attached to a skill or effect. By no means a laser show. We’re using really good GPUs, but that’s what graphics settings are for. I don’t know of a better way to determine your “position” on the arc other than finding the percentage of the angle that you have covered so far.

That looks pretty good to be honest. What is the angle uniform value? The angle to the shadow’s edge?
I have my own LDR implementation of this kind of lighting from very long ago. I used this article: http://archive.gamedev.net/archive/reference/programming/features/2dsoftshadow/index.html. I’m pretty sure you must have seen it as it is the best article on 2D shadows on the web. I’ve noticed you don’t take the light’s physical size into account, which is the reason penumbras exist. You also don’t seem to have any problem with penumbra overlapping the object casting it, see this page of the article: http://archive.gamedev.net/archive/reference/programming/features/2dsoftshadow/page5.html, which was the reason I never implemented soft shadows. I’m pretty sure you’re just making the shadows “smaller”. Wouldn’t that mean that you are not able to have objects touching each other? I mean, put two of those boxes next to each other and you’d get a stream of light passing through them if you place the light just above or under them? Badly explained, but look at this:


       \  / <- bugged penumbra
        \/
+-------++-------+
|Block 1||Block 2|
+-------++-------+

Light:  ><

The >< is supposed to be an X. The blocks are touching each others. Try this out… xd

[quote]What is the angle uniform value?
[/quote]
The angle is the length in radians of the penumbra. It’s usually around 3 degrees wide, it’s just an angle between the two vectors coming from the corner of the hull that make up the penumbra.

For the physical size no we don’t have this implemented yet and would have to modify to achieve it.

We don’t actually even have code right now that can handle shadows for anything other than a box, for the simplicity of getting some working code down. When we extend it to complex geometries we’ll definitely use this site to make sure it’s as realistic as possible. For the penumbra we don’t actually make the shadow smaller, we actually draw “more” shadow over the light, using the fade function. It might not be the most realistic and I haven’t tested the case that you described below but that’s definitely a consideration. If that were ever going to happen we’d probably just put the two bodies together and make them one.

Definitely a work in progress but it’s way more than we had two weeks ago :slight_smile:

Ah, yeah, you seem to have it that out well. If you have an angle for the penumbra size, you can easily take the light size in consideration by changing the penumbra size. If you also make the shadows larger for the penumbra, then I guess it’s fine. Still a little concerned about what happens with two shadow casters close like I described…

I haven’t tried and I’m not home right now, but I can ask my buddy to look into this… I’m really not sure to be honest.

Hey guys, I am the other developer working on this project with rejechted.

Here is the pic of the two blocks touching that you asked for theagentd. The penumbra doesn’t get bugged, but the shadow from one block does overlap the other block a bit. This isnt realistic but im not really sure how we would avoid it.

You can also see that we implemented a flashlight on our character. We used the same shader that we used for the shadow penumbra to give the edge of the light a nice fade.

Nice! I wonder why it doesn’t look bugged though… xD Well, if it works, I’m not complaining! About the blocking, you could probably add some code to your blocks to make some edges not cast shadows. That way you could “disable” shadows for the bordering walls. It will also be very useful or even needed if you’re creating more complex objects, as the seams would be very visible when lit.
You could also make the flashlight look a little better. It has a little too sharp edges right now, don’t you think?
Overall great work!

At the moment the flashlight is literally a point light that draws a triangle fan for a certain number of radians, so the beginning of it would have to be masked behind a flashlight image or something. Surely there are better ways. This is still a sandbox though, but we’re aware of the flaws

Just a though: the blocks casting the shadows look unnatural, completely lit. It would probably look much better if they would be selfshadowed. Like being darker away from the lightsource and have some specular on the facing side.