Laserbrain Studios

Games Forum Blog Contact

Improved lighting technique

June 9th, 2014 by Christian Knudsen

There have been a bunch of improvements to Hostile Takeover‘s visuals in the past year. I’ve upped the graphics from 24-bit to 32-bit, since it seemed more and more silly to sacrifice visuals for better performance on low-end computers. And I also abandoned the older, more retro UI in favor of a somewhat more modern and less obtrusive design.

But one of the changes that took the longest to implement was the new and improved lighting system. Not because it’s all that complex, but because it took some tinkering and experimentation to figure out how to do it right. So that’s what I want to talk about in this blog post.

In the below image, you can see the 3 levels of lighting quality that you can set in the game’s options menu. These 3 levels represent the lighting system as it has progressed since I first started working on the game. Instead of just using the highest quality in the game and scrapping the older versions of the system, I decided to allow players to set the lighting quality in the game, since on older computers, lowering the quality can improve frame rate slightly.

The 3 levels of lighting quality

The quality 1 lighting just considers the lighting level of a single tile. The floor sprites have the level of lighting of the tile they’re on, and the wall sprites the tile they’re facing.

With quality 2 (which is what was available in the old releases of the game), the lighting is smoothed between adjacent floor and wall sprites. To achieve this smoothed effect, I use vertex coloring. In OpenGL, vertices are basically the corners of the texture you’re drawing to screen. So when drawing a floor or wall sprite to screen, they’re drawn as rectangles (‘quads’ in OpenGL) and therefor each have 4 vertices:

A floor sprite A wall sprite

When drawing one of these sprites to screen, I can tell OpenGL how light or dark each corner of the sprite should be, and OpenGL then smoothes out the light level across the entire sprite and between the corners. To make adjacent floor and wall sprites blend more into each other, I set the light levels of the corners to be an average of the sprites that share that corner.

This works fairly well and certainly gives smoother lighting than for lighting quality 1. It’s not perfect, however, and as you can see in the comparison image, there are still some hard edges between the individual floor and wall sprites. The reason for this is that the corners of the actual floor and wall images don’t line up with the corners of the sprite. The floor is diamond shaped, while the texture is a rectangle. And because of the isometric perspective, the corners of the actual walls don’t line up with the corners of the sprites either. To fix this, I split the sprites into sub-sprites when drawing them to screen:

A floor sprite divided into sub-sprites A wall sprite divided into sub-sprites

This gives me sprite corners that line up with (some) of the floor and wall corners. And since the floor and wall corners now line up with the sprite’s corners, the vertex coloring makes the smooth lighting match up better between adjacent floors and walls. As a result, the transition between adjacent floors and walls is practically seamless. Here’s how the corners of a wall’s sub-sprites matches up perfectly with the corners of an adjacent wall’s sub-sprites:

Sub-sprite corners lining up perfectly

I’m really pleased with this system — not least because I’m now getting almost perfectly smooth lighting without any use of shaders or other more demanding methods.

This post has 4 Comments on the forums.