Lighting techniques
Posted: Fri Oct 06, 2006 1:23 am
The only way to get the lighting to look any better than it already does is to use per-pixel lighting. The OGL hardware lights are per-vertex only unless you use their values in a pixel shader. Regardless, it's still only 8 lights so it's not really viable. I don't know how you would work around that limitation even with only static lights, short of using blending or combining lights.Diedel wrote:I also tried to add OpenGL hardware lighting, but OpenGL only supports 8 lights (at least on NVidia and ATI hardware - actually this is up to the driver developer, OpenGL only demands at least eight), and D2 levels usually have a lot of static lights already, not to speak of dynamic lights during fights. So I tried to do this with a vertex shader, but there are so harsh limititations on shader programming that it looks like that will become a failure too. This is very disappointing. Hardware lighting looks quite a bit better than D2's static and dynamic lighting (particularly the latter).
I could work around that limitation for static lights, but dynamic lights render that task next to impossible.
You could calculate the intensity values per-vertex on the CPU (which D2 already does), and pass them into a vertex/pixel shader pair, which will interpolate the values per-pixel. This wouldn't be terribly difficult to slap on I would think, however it wouldn't look all that much better since the lighting data is still per-vertex (ie, putting a flare on the middle of the surface will not light it up very well compared to putting it in the corner).
Since pixel shaders have texture lookups, perhaps you could upload a texture each frame that stores light positions (dynamic lights only is best, and use vertex lighting for static lights, for both performance and level design reasons)? You'd need to pack positions into multiple pixels to maintain the needed level of accuracy. If you used four pixels per light position on a 16x16 texture, that'd give you 64 lights to loop through for each pixel (you could pass in the actual number of lights as a..oh, I forget the parameter types...fixed I think. dunno if anything less than SM3.0 will let you base your loop on a non-constant though). That's quite a few, though you can easily pass that up with more than three or four players in a multiplayer game. hrm, and another thing to consider is light intensity and color. Since light is additive, you could scale the color to an appropriate intensity and store that in a fifth pixel. If you shift the whole color value down a bit or two on the CPU and fill in those bits with overbright information, shift them back up by that amount on the GPU, you can do overbright effects without significant loss in intensity precision (Q3A achieves its overbright effect by tweaking the textures and the display's gamma curve). Maybe using three pixels for position would be sufficient, so you could keep everything in nice 4 byte sets. You'd have to test that obviously.
And of course, since I have very little actual graphics programming experience, I have no idea how it'll perform. 256 texture samples per pixel is a lot to choke down for most video cards. It'd be a good idea to combine lights somehow. You could resort to using multiple 8x8 textures, use one texture unit for switching between them so you don't have to do any switching in your shader. Since lights on one side of a room won't necessarily affect the other side, you could separate levels into light regions through approximation of cube volume and use a different 8x8 texture for each region. It would duplicate storage (lights would frequently wind up on multiple textures), but it would guarantee constant performance since no face in a cube will see more than one 8x8 light texture.