Obstruction of Visibility - Beer's Law


No no no, Beer’s law is an actual thing that exists in actual physics - and I used it in Asteroid Arena. In this tech blog I’ll share with you how the clouds and obstacle visibility obstruction works in the game. Asteroid Arena is built from scratch with no engine nor middle-wares, and this was one of the first tech related problems I tackled. But before we dive in completely, let’s start at the (almost) beginning.

When the game was but an infant, there was a spaceship flying around in an otherwise empty universe that wrapped around itself. From here came a simple idea: How about it not being empty? Maybe some nebula clouds or something could be there? A simple idea to try out. So I added some diamond-square generated clouds (which I later replaced by a better algorithm - maybe more on that in a later post) and rendered that on top of everything else. Now all of the sudden, you could hide your spaceship inside the clouds! The problem is that drawing clouds on top of everything else isn’t how clouds behave in real life. In real life you can see through them a little bit, especially as you get closer. Can’t we do that in the game?

Meet Beer’s law (or Beer-Lambert law if you prefer). Beer’s law says how much light is “absorbed” by a density of particles. Many games use this to render fog, and even OpenGL used to have fog built-in (look up glFog), but these games usually assume uniform fog density (i.e. the fog has the same thickness all over). Asteroid Arena fog densities are not uniform.

For uniform fog densities it’s easy to calculate how much light is absorbed because the math results in just a single exponent calculation per pixel. But if it’s non-uniform you have one additional step, which is ray casting through the fog and summing up the density. In other words you have to look up the fog densities from the observation point (the “camera”) to the end of fog that you see. For Asteroid Arena (which is 2D) this meant:

  • For each pixel on screen
    • For each pixel between the observer (i.e. your ship) and this pixel
      • Sum the thickness
    • visibility factor = e^(-constant * calculated sum)

Sounds like the performance is going to go to hell. I first started doing a CPU implementation of this but quickly realized the performance is never going to even hit 1 FPS. So I gave it a go on my already out-dated GTX 660 Ti graphics card - and it performed at around 100 FPS without breaking a sweat with pixel sized stepped tracing.

This little tech trial completely changed the look and feel of the game and is something I haven’t seen much of in many other games. Hiding (or being a little chicken if you prefer) inside a cloud was now a feature. I later added “see throughness” functionality so that when you hide inside a cloud, or behind an asteroid, you can still see an enemy ship approaching. This also makes asteroids inside clouds stand out more so you don’t accidentally keep bumping into them (which was annoying).

The approach above worked very well for a long time, until I tried it on an integrated GPU where the game ran at 10 FPS. At this point a couple of things had to change but more on that in a later post.

Get Asteroid Arena

Buy Now$3.99 USD or more

Leave a comment

Log in with itch.io to leave a comment.