Lighting in Alien Blitz
In Alien Blitz static lights were calculated on the CPU into an array, the values were then stored into the terrain mesh in vertex properties.
The vertex shader was reading these values and forwarding them to the fragment shader for rendering.
Dynamic lights on the other side where saved into a texture, and inserted on top of the map in the fragment shader.
The main advantage is that it is quite quick to compute, and doesn’t need that much updates, but there are multiple drawbacks :
- This task is done on the CPU, harder to optimize
- There are a few artefacts
- Light combination is not easy, and leads to some dull colors
- When the map updates (door open, wall destroyed), etc… the lights will not update properly, see example below
Real time light on shaders
There are lots of ways to handle lighting in 3d, the first approach I was thinking about was to do it using shadow mapping, after all I made a tutorial on this subject !
But I wanted to try something else, that I hope is less GPU intensive, especially for fast light that needs frequent updates.
What I need to do is :
- Send all visible light information to shaders
- Since I am using a top-down view, there is always a limited number of lights visible at any moment
- I am currently sending : position, color and intensity.
I will need some more information to make directional light work, but I don’t need them at the moment
- Send a height map of the current level
- Levels are composed of cubes, so everything has nice integers positions
- My levels are semi-3d, they are 2d map with added height information. This is possible since the game is a top-down view, so adding “floating” cubes above the ground would not make sense (only floating elements are sprites, that do not affect lighting, and are barely used anyway)
And with these elements in the vertex shader I can decide if any vertex is illuminated with a light, I am basically tracing a line (using Bresenham algorithm, for 3d) between the vertex and the lights, if the line encounters an obstacle (if line is drawn inside a wall in the height map) then it means vertex is not illuminated by the light.
This allows me to compute, on the vertex shader, all visible lights for a vertex, and apply the resulting color in the fragment shader.
This is not a perfect approach, but works nicely in my case because :
- the map is not fully 3d, this is a 2d map with height information
- the map is made of cubes, and so makes all computation easier
Now there is real time lighting, which removes all the disadvantages of the previous lighting system.
Of course there are now other problems because maps/lights where not intended to work that way when designing Alien Blitz :
- lights are now too colored (they where exaggerated before in order to avoir dull lighting)
- sun light was simulated using multiple invisible point lights with great range, which is now visible in the above screenshot (we can now guess where the invisible light is located thanks to the shadow in the room)
It seems as if the sun was on the horizon because of this.
But for a future game, with new maps and lights, this will be very nice.
Normal mapping
The good thing about having light information sent to shaders is that I can now work on normal mapping for the terrain textures.
To make proper normal mapping calculation I need :
- light position
- normal of the wall
- a normal map for each texture
Light position is now available, so no problem with that one
The normal of the wall is quite easy to get in my case since I am only working with cubes, so there are only 5 normals each time (6 minus 1 since bottom faces are never visible). It also makes vertex operations a lot quicker.
The normal map needs to be manually done for each texture, but I wanted something to test quickly so I decided on another approach :
Starting from the classic textures :
I apply a simple grayscaling algorithm :
And I now work with this texture as if it was an height map :
For each point I look at the color value of the point around, deciding if I must add a x/z component to each normal depending on the color difference with each point.
And this is the resulting normal map
I must say that it is quite accurate, it works probably because my textures where made of a basic color that was just darken when drawing shapes.
Anyway this is a good approach. And I can see myself working with that algorithm for a future game.
Basically instead of producing the normal map using blender, I can keep working on gimp all the way, producing the texture and the corresponding height map at the same time. It is much easier to make an height map for small texture like that than to produce a normal map.
You can see quite the difference on the ground near light, this adds quite more details and this is very nice actually playing with these improved lights.
The downside I currently have is that I make light tracing calculation on the vertex shader, it means in the fragment shader I don’t know whether a light is visible from a given point. And as such the normal map is not applied correctly (a light that is behind a wall may impact texture lighting if it is close enough).
I don’t know yet if I can make this type of light tracing in the fragment shader, or if I can share this type of information between the vertex and the fragment shader. I need to perform some tests, maybe it’s not too GPU intensive, no idea yet.