Hey everyone, my name is Conor Dickinson and I am the CTO and co-founder of Cloud Party, a WebGL 3D social content creation and discovery platform. I work on all sorts of things but my interests and experience lie primarily in 3D rendering effects.
This is the first of three technical articles detailing my recent work on improving the look and customizability of the skies in Cloud Party. Part 1 (this one) will cover background and research on sky dome rendering; part 2 will go into detail on the implementation and optimization of the sky dome rendering technique; and part 3 will cover the details of the cloud system. I hope to provide some insight into how graphics techniques are developed from research to implementation to optimization. I will also give you the code so you can make your own skies look better and hopefully improve on these techniques!
TL;DR? Ok fine, go check out the demo!
In Cloud Party we allow our users to customize almost every aspect of their 3D scene. A pretty major component of any outdoor space, visually speaking, is the sky, so of course we allow customization of that as well. Up to this point, however, the specification of how a sky dome is rendered has been pretty basic: it is just a list of meshes with any user-specified material applied to it.
This is great for an artist who knows how to make hand-painted static skies, but not so great for the average user. Old Cloud Party skies did not react to a change in sun angle or intensity; nor were they particularly easy to modify, since most of the sky dome properties existed in a 1D texture used by the material.
Ideally we wanted a solution that looked good, reacted to the sun, and had adjustments available to users. We wanted to keep the existing solution as well, for those who are going for something non-realistic or just want a very custom look to their sky.
One note: the “sky” asset type in Cloud Party actually includes specification for many other scene-wide graphical effects, such as ambient lighting, ambient occlusion, light shafts (also known as light scattering or “god” rays), and fog. For the purposes of this article, however, I am just talking about sky dome rendering.
The question has been asked since people first looked at the sky, but it isn’t until fairly recently that the process behind this everyday phenomenon has been understood! The earth’s atmosphere is made up of many particles of varying sizes. These particles get in the way of light coming in from the sun and scatter some of that light in random directions. Small particles scatter blue light more than red light (this is known as Rayleigh scattering), whereas large particles scatter light frequencies more equally (which is known as Mie scattering).
When you are looking at the sky (not directly at the sun), you are seeing the blue light that has been scattered away from the sunlight’s direct path and then bounced around a bunch of times before reaching your eye. This is called “in-scattering”, because it is the light that is scattered into your view. Since the blue light has been scattered away from the sun’s direct path, that means the light arriving from the sun (what you see if you look directly at the sun, which you should not do) is less blue. This is called “extinction” and it explains why the sun appears yellow.
In this diagram the sun is overhead; the yellow lines are the incoming light rays from the sun that in-scatter into view along the green line.
So why is the sky orange/red at sunrise and sunset? Well, when the sun is low in the sky the light has to travel further through the atmosphere, meaning more of the blue light will be extincted before it gets in-scattered, making the in-scattered light red.
You can see in this diagram that the light rays have to travel much further through the atmosphere at sunset before they in-scatter into view, allowing more opportunity for the blue light to scatter away.
As you can imagine, calculating where sunlight ends up after bouncing around and around in the atmosphere is prohibitively expensive, so we will have to make some assumptions and simplifications to make this work in real time.
I always start any project like this by researching what academics and other industry experts have done. In this case, I did not find many articles published recently about real-time sky rendering. My guess is that this is because most modern games do not require or even want procedurally generated skies. Nowadays they have enough GPU memory to hand-paint a 8192x2048 texture and just draw that in the sky. That’s what we did in Tomb Raider, and they were absolutely gorgeous! The downside is that they require the talents of great artists to make, and are mostly static (usually they put a couple of layers of scrolling textures in front for clouds).
One popular approach to solving the complexity of atmospheric light scattering is to precompute it on the CPU (either on demand or as part of a build step), then use the precomputed results at runtime to remove some or all of the calculations. I used this method for the sky rendering in Star Trek Online, mainly because I used the same tech for rendering the atmosphere around planets as seen from space, and in that case you can’t make as many simplifications to the equations. The results were rather nice, but generating the 3D precomputed texture was quite time consuming and the results ate up quite a bit of texture memory.
In my next post I will go into detail about my implementation (which is similar to Florian’s technique (see below), except I make some further simplifications to make it run faster) including shader and CPU code you are free to use in your own projects. In the meantime if you have a WebGL enabled browser you can go play with the sky dome renderer.
ATI published a paper in 2002 including simplifications of the light scattering and extinction functions: http://www.ati.com/developer/dx9/ATI-LightScattering.pdf
This GPU Gems chapter from 2005 has a great background of the atmospheric light scattering problem, and was the basis for the work I did on Star Trek Online: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html
Florian Bosch wrote a nice article in 2011 about his implementation of sky dome rendering in WebGL, and it includes some good diagrams: http://codeflow.org/entries/2011/apr/13/advanced-webgl-part-2-sky-rendering/