In a previous post I talked about a method to do Phong shading using a pixel shader. This method produces great results but is too slow to use for a large number of polys that are re-rendered on every frame. So I wanted to find a faster way to do lighting for a part of the game that renders more frequently.
I first considered rendering the lighting directly into the texture for each poly in a semi-offline fashion and then just applying the textures. Since shaders can be run asynchronously, it would be possible to do this in the background as the player explored the world. The downside of this is that it requires a lot of memory and, on a single core machine, it would be asking a lot of Flash to do this without stalling the frame rate.
Instead, I thought I would try using a GradientFill (i.e. beginGradientFill or GraphicsGradientFill) to do some Gouraud shading. GradientFill has a Matrix parameter that allows you to modify the gradient any way you want but unfortunately, the documentation is silent on the subject what exactly this Matrix looks like. It pretty much just tells you to use Matrix.createGradientBox() and don't ask too many questions. A little reverse-engineering later I figured out that Gradient space is a square centered on the origin and with sides that have the bizarre size of 1638.4 (2^14 / 10). Knowing this, it was pretty straightforward to calculate the lighting value for each vertex and fill a triangle appropriately.
Here is a demo:
Mouse controls the light position; click to switch between sine waves and Perlin noise. Source code here.
I'm pretty happy with the results of this. Obviously it suffers from the normal problems with Gouraud shading such as not handling intra-poly highlighting and sometimes outlining edges but otherwise it seems like a good compromise between Phong and flat shading.