Upcoming Events
Southwest Gaming Expo
11/20 - 11/22 @ Dallas, TX

Workshop on Network and Systems Support for Games (NetGames 2009)
11/23 - 11/25 @ Paris, France

ICIDS 2009 Interactive Storytelling
12/9 - 12/11 @ Guimarães, Portugal

Global Game Jam
1/29 - 1/31  

More events...


Quick Stats
6713 people currently visiting GDNet.
2341 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

Link to us

  Intel sponsors gamedev.net search:   

This rendering algorithm is based on the SIGGRAPH93 publication: "Display of The Earth Taking into Account Atmospheric Scattering" by Tomoyuki Nishita, Takao Sirai, Katsumi Tadamura, and Eihachiro Nakamae (which I will refer to as Nishita for the rest of the article). The link to this publication can be found at: http://nis-lab.is.s.u-tokyo.ac.jp/~nis/abs_sig.html#sig93. If you haven't read it, please read it before you read this article. You don't need to understand the math in it, but you do need to understand the concepts.

Oh, and read the README.TXT before you run the prototype. If someone sends me an email with a question that was answered in the README.TXT, the next version I publish will open it automatically for you every time you launch the program, and it will crash if it can't find the file. ;-)

Disclaimer: If all you need is a pretty skybox, this article is not what you're looking for. If you need an animated skybox with awesome sunsets and clouds, this article still probably isn't what you're looking for (but it might give you some ideas).

I wrote this article because I've wanted to implement realistic real-time atmospheric scattering for my procedural planet renderer for a while now. If you're interested in seeing it, go to my home page at http://home.comcast.net/~s-p-oneil/, run the demos, and follow the links to the Gamasutra articles I've published.

Before I started this, I saw a lot of questions about atmospheric scattering on the forums. I also saw a lot of great answers, but they weren't really the answers I needed. Unfortunately, being able to accurately render any type of planet or moon from any viewpoint with any type of atmosphere means you can't cut many corners. You can't assume that the density of the atmosphere is the same everywhere. You also can't assume that the scattering constants, or their dependence on wavelength, will be the same everywhere. This disqualifies most of the really useful optimizations before you even get started.

The demo, which I am providing with complete source code, doesn't render a planet and it doesn't render a sun. It currently renders the empty atmosphere shell, much like Figure 6 in Nishita's publication. It renders the outside of an inner sphere to show the scattering reflecting off the planet's surface, and the inside of an outer sphere to show the scattering that just passes through the atmosphere. It implements both Rayleigh and Mie scattering, and all of the constants can be modified at runtime within the demo.

The Problem

The primary optimization Nishita described was to pre-calculate a lookup table of the optical length between the sun and every point in the atmosphere. This is possible primarily because the sun is so far away that the sun's rays can be considered parallel. Unfortunately, this leaves you with the costly calculations of determining the optical length between the camera and every point in the atmosphere, if and where each ray from the camera enters the shadow of the planet, and the nasty integral over some expensive exponential equation that involves both optical depths (which are themselves nasty integrals over some other expensive exponential equation). One of the nested nasty integrals is taken care of by the lookup table, but the other one is not.

Math refresher: For those of you who haven't learned (or don't remember) what an integral is, don't worry about it. In its most basic form, an integral is simply a sum of values across a range. Programmers write loops that calculate sums all the time, and that's one way to solve an integral equation. To calculate the approximate optical depth along a ray, you simply break the ray up into a bunch of smaller "sample" rays, then loop through the sample rays summing the results of the equation (density * length) for each of them. The smaller the sample rays are, the more accurate your results are.

Now I'll explain just how painful these calculations are, even using Nishita's optimization. If you take 10 sample rays and the problem is nested, then you have to solve 10*10 expensive math equations per vertex (10*20 without Nishita's optimization). Multiply that by 3 because you need to calculate each one separately for each color channel (red, green, and blue). Multiply everything again by two if you're doing both Rayleigh and Mie scattering. We're up to 600 equations per vertex now, and don't forget to determine whether the ray went into the planet's shadow. If you want this to be real-time, it's easy to figure out before you start coding that this approach won't work.





A Better Lookup Table

Contents
  Introduction
  A Better Lookup Table
  Optimizations

  Source code
  Printable version
  Discuss this article