Tuesday, March 29, 2011

A Valley Without Wind Pre-Alpha #8 -- New Lighting Test

This video is just a simple lighting test showing off our new way of handling light in AVWW. The older method, using the z buffer, is still available for lower-end graphics cards and computers, but this new model looks way better, and on most computers won't use that much more CPU/GPU!

What We Were Doing: The Z Buffer
The problem with the Z Buffer method is that it winds up with very pixelated edges.  That buffer doesn't support anything except binary write / don't write data, and that's not super conductive to having high quality lighting.  The plus side is that it's super compatible with older graphics cards, and it doesn't use much at all in the way of GPU power.

The #7 video was using the z buffer, but was also using a trick for the "eyesight" part of the view to make it look like a gradient when the z buffer doesn't really support that.  The trouble there is that you can't do that with anything that overlaps in the z buffer; so I could do that for eyesight, but not for lights.

What We Tried Before The Z Buffer
Why not just use the normal 3D lighting model that most 3D games use?  I tried it, but the problem is that this is a 2D game being rendered using 3D quads.  That just really didn't work out, because pixel lighting is incredibly expensive on the GPU, and not supported by every card, while vertex lighting is incredibly coarse and looks really bad.

To make matters worse, the way that we draw things in Unity 3D is by using their Graphics.DrawMeshNow method.  Supposedly that supports lighting, just not certain kinds of lighting, but my experience was that even vertex lighting was fraught with errors.  Based on the materials in use, I'd get random aspects of the lighting shutting on and off in various parts of the scene.

I tried using Graphics.DrawMesh instead, but that in turn doesn't support things that I need to do with uv animations and such for textures.  As I discovered with Tidalis and AI War, Graphics.DrawMeshNow is basically the only possible solution that has any substantial speed for the number of sprites that we need to draw, while also supporting all the functionality we need in terms of fancy texture mappings.

So that meant that a traditional lighting model was basically out.

The New Method
The new method is actually conceptually simpler than any of the others, and doesn't really do anything new technology-wise.  I thought of doing this from way back, but never thought it would look very good or perform very well.  After the #7 video, and some prompting from long-time Arcen community member eRe4s3r, I decided to at least give it a shot.

What I'm actually doing for perfect darkness is rendering an array of big black circles with fading-to-transparent radial gradient edges to them.  These circles are about 256 pixels in outer diameter, but on the pure-black internal diameter they are about 64 pixels.  Each one of these is rendered in a grid that is screen-aligned and 64 pixels per grid tile.

Talk about an inefficient way to draw blackness!  But the cool thing happens when you start "carving out" blackness where there is a light source.  Every frame, each light source writes into that big screen-aligned array if it is providing some light to it (in a framerate-independent manner, of course).  Also every frame, at about half that rate, each tile loses light.

The longer the light is in one location, the closer towards perfectly-invisible that black circle on all the tiles near it get, until they disappear and it seems perfectly bright.  Since the images drawn in each tile are so much larger than they need to be, their gradient edges "hang over" into the nearby tiles.  I also have each image pulsing by about 10% on a 4x speed sine wave, which makes the edge of the darkness seem to pulse in a living, threatening manner.

The other effect of all this is that when you turn move a light source, it takes a minute to fade.  About half the time it took to create the light source in the first place.  This means that things like the fireball, which flicker and sputter in a seizure-inducing fashion if there was no slowdown, instead look graceful and almost liquid.  This is darkness with substance, which is a pretty neat stylistic effect, and in keeping with the visual style and themes of the game.

How Does This Integrate Into The Game?
This new effect adds a lot of extra draw calls into the game, and so on some very old GPUs it might stutter some.  These would be the same computers that would need to turn shadows off in the game, and might even need to turn foliage down.  To make sure those sort of machines can still play the game, we now have a settings option where the lighting model can be chosen.

The z buffer method is functionally equivalent to this new one, it just looks worse, but it's more efficient.  For people with astronomically large screen resolutions, they may also prefer that, as the cost of this lighting model gets linearly higher with the number of pixels in the screen resolution.

On our test machines, we haven't found this new approach to be very heavy at all, though, so we suspect most people will leave this turned on by default, as they will shadows, foliage, and so on.  If you can comfortably run AI War, you can comfortably run this, too.  But in terms of netbooks and other smaller computers that can run Tidalis but not AI War, let's say, we also wanted to have options for them with AVWW.  So far it seems we do!


Jay said...

That is a major improvement. You can really see some of the atmospherics coming together. This game will certainly have a unique look. Thanks for sharing, can't wait to play it!

Ryan said...

This looks PHENOMENALLY better than the lighting in vid #7!!!!

Wow, I'm so relieved that you've implemented this... I was quite turned off by those hard edged lamps and horrible, seizure-inducing fireballs.

Lusit said...

This looks absolutely phenomenal, Christopher. Really, brilliant idea.

My only suggestion is that, with the eyesight lighting, it doesn't protrude so much out the back, and it isn't super bright around the character. Have it slightly darker the farther away from the character, instead of super bright and then sharply getting darker. It'll look more natural, and cause more suspense as you're exploring dark areas.

Really, great work.