GameLoom Studio in Instagram GameLoom Studio in Facebook GameLoom Studio in Itch.io GameLoom Studio in Steam GameLoom Studio in Discord
Older blogposts ≫

Obstruction of Visibility - Temporal Beer's Law (1/2)


No no no, Beer's law is a real thing…

… and I used it in Asteroid Arena for cloud visibility calculations. 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.

The not-so-big bang

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?

Highlighted areas indicates partially hidden-from-view regions.

Here, hold my law

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.

Beer's Law.

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 cloud thickness
    • visibility factor = exp(-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.

Everything is better with clouds

Scene without visibility modifications.


Visibility obstructors (stored in RGBA for no good reason).


Raycasting result (black is fully visible, white is fully blocked).


Fully rendered scene.

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. Thankfully I managed to fix that, see next blog post for that!

- Jens the Hidden Programmer, June 2024

This blog post was originally released on itch.io March 2023

Older blog posts:

2024

Obstruction of Visibility - Temporal Beer's Law (1/2)

Obstruction of Visibility - Temporal Beer's Law (2/2)

2022

Portability and the Demo Effect

Iterative "KIS(S)" - The Sprite Atlas

About Animations…

Asteroid Arena - How It All Began