September 29, 2009

Bamf: DevLog 4 — Advanced Lighting

Alright, so now we have lighting! At this point I went back and tweaked the physics more, and started working on enemies that look around for you and pay attention to how lit up you are and other cool stuff like that. But to make this easier to read through I'll skip ahead to where I went back and worked on the lights more.

When I first did the lights, they actually didn't look like the screenshots I show in the last post, with the nice gradual shadow that got darker the farther you got from the light. Instead each one would draw a bright circle, and then a bigger dark circle:

You could control the size of the circles though, and it actually looked alright, and divided the levels clearly into 'dark', 'dim', and 'bright'. But mainly just to see if I could, I instead had each light draw a radial gradient, ending up with the gradual falloff shown in the last post.

Then I went further. See, in these examples, the shadows are very sharp and clear, but in real life, shadows have slightly blurry edges. Sometimes. It's kind of taken for granted that shadows are blurry, but they usually are not. What causes blurry shadows is when last is being cast from an area instead of a single point. The smaller the area the light is coming from, the sharper edged the shadows will be. But when you have a large area, there's a portion of the shadow that's hit by *some* of the light. And that slice gets bigger as you get farther from the light.

In the first example, we're tracing the shadow based on where the center of the light is. We find the angles to the corners of the object (red lines), and draw the edges of the shadow (blue area) based on those angles.

If we take into account the entire light, we get this diagram:

The area between the two lines is where the light is partially blocked, and because it gets wider as you go, the shadow gets blurrier the farther away you go.

There are many ways to recreate this effect when you're drawing in a program. One way is to calculate this area where it should be partially blocked, and draw a gradient between the two lines. I didn't choose this method.

Instead, what I'm going to do is make each light act like a small collection of lights scattered around within a small area. The light from each will each cover a slightly different area, and slightly overlap with the other lights, making soft edges on the shadows.

Here's a comparison of a simple light and a so-called 'area' light:

Not only do the shadows look nice and blurry, the blur hides the jaggy edges really well, making the shadows look more like they were painted in. So I call this a win.

Now for the sun. To get outdoor lighting we don't want to just place a bunch of lights all over the place outside the buildings. The sun casts light from very far away, casting all the shadows in the same direction. So we'll make a new type of light called a directional light, and for this type of light, the edges of the shadows will just always be a given angle, instead of based on where the light is. Throw one of these in the level, tell it to make the shadows all going down and slightly to the right, and you have sunlight.


This directional light also works sort of like an area lights: It's acting like a collection of lights, each casting shadows at a slightly different angle. Even though the sun is very far away, it's also very very big, so it's still technically an area light. The effect is probably not as dramatic as it is here, but I don't know the exact measurements so I'm just eyeballing it and using what looks good. As mentioned before, the blurriness hides the jaggy edges, so it's probably fine for this to be too blurry.

But, real life doesn't have pitch black shadows like this, right?

This is for two reasons, one of which is easy to duplicate. The first reason is light bounces off things, it doesn't just stop. Hold up something white and it will reflect light back into the room. This is time consuming to accurately model in a game. Mainstream 3D games are still not doing it, instead faking it with other methods or calculating it beforehand.

The second reason is when you're outside, light isn't coming only from the sun. The sky actually catches and scatters a lot of light, sending it every which way and generally filling all the shadows with light unless they're totally blocked from the sky. There's a simple 3D rendering technique called ambient occlusion that mimics this. For every point in the scene, it measures how much of the sky is visible from that spot. The less sky it can see, the darker that spot is. You can fake this by simply placing a bunch of directional lights all over the place, all aimed at the center of your scene. I did this for a couple projects in school because real ambient occlusion takes a very long time if you want it to look nice.

So I just have a light that works sort of like an area directional light, except instead of only slightly different angles for each pass, it renders roughly 160 lights, starting from point directly right, and increasing by small amounts each time to cast light down and right, down, down and left, and finally ending up pointing directly left.

The end result of this is, light is coming from every direction except down. Here's an example of this ambient light by itself:


And here's what it looks like added to our scene (without on top, with on the bottom):

Cool, now we've got light streaming in through doorways and windows, and the outside feels very bright and outdoorsy, especially compared to the lighting inside. It also means we only have to place two lights in any level to create outdoor lighting: a directional light and the 'fake' ambient occlusion light.

Next post: Tweaking the controls and physics.

No comments:

Post a Comment