Atmospheric Scattering

Howdy folks,

Over the weekend I found out just how hard it is for a not overly mathematical person to make heads or tails of the atmospheric scattering maths in research papers. I also found out how hard it is to find working example code (Java or otherwise) that shows even the most basic scattering equations working.

So, I present to you, an implementation of the GPU version of Sean Oneill’s atmospheric scattering.

http://pastebin.java-gaming.org/75c4464703b

I don’t promise that the code is pretty, or very well written, but it works (and there are sunsets).

Notes:

  • It uses LWJGL
  • There are magic numbers I haven’t quite figured out yet

Cheers,
Brett

Edit (Added PAMD code links from this post):

Simple (and slow) BufferedImage implementation of “Practical Analytic Model for Daylight”
https://docs.google.com/folder/d/0Bw97A7hoqbmPcGpVNEd6UnprSms/edit

Libgdx based shader implementation of “Practical Analytic Model for Daylight”
https://docs.google.com/folder/d/0Bw97A7hoqbmPcGpVNEd6UnprSms/edit

If you care, I can point you to where most of the numbers come from.

Nice! It really is a beautiful effect!

The first time I heard about atmospheric scattering was here. They seem to precompute much of the algorithm. Your shader is a bit hard to read since it’s hardcoded, but I don’t think your does. What kind of performance are you getting?

Screenshot or it didn’t happen.

I really like how Atmosphere is rendered at Reset. Usefull blog post about implementation here http://reset-game.net/?p=284

Yes please!

Some of the things are easy, its just ones like the Rayleigh scale depth, or trying to figure out why if I draw the sky sphere with size “atmosphere radius + 1” (i.e. just outside the atmosphere depth) it doesn’t work properly, but if it is drawn at “atmosphere radius * 1.5” does.

Cheers,
Brett

On scale depth: Hehe…good thing you asked 'cause I happen to know the answer and it’s an ad-hoc solution: SEE Section:

16.4.2 Eliminating the Other Dimension at http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html

For the second: Don’t do that. :slight_smile: You have no reasonable expectation that a function will operate reasonably outside of range.

Looks like I’ll have to re-read the papers and articles to figure some more of this out.

Because of planetary scale? If so then that’s part of the simplifications, so simply use a uniform scaling to make the desired match the legal range. You could look at “Precomputed Atmospheric Scattering”, but that requires a bunch of texture lookups. Performance win? More flexible? Don’t recall…I skimmed it when it was new.

Aside: Near ground, so sky is a flat slab instead of spherical shell is much simpler. “A Practical Analytic Model for Daylight” & “A Physically-Based Nightsky Model”

Somewhere in the dim dark past I remember reading “A Practical Analytic Model for Daylight”.
I will have to revisit it I think. Thanks for the reminder :slight_smile:

No problem. If you want to beat your head against the wall of planetary scale scattering…pretty much all models are derived from the ones in:

“Display of the Earth Taking into account Atmospheric Scattering” & “Display Method of the Sky Color Taking into Account Multiple Scattering”. So you could follow citation chains to find various choices.

BTW Kids, if memory serves me, these papers cover much more about rendering planets than just atmosphere.

After Roquen reminded me about the paper, I spent this weekend getting a basic version of “A Practical Analytic Model for Daylight” working.

The code is based on the Sky Dome class from JME2, with the bits I didn’t need removed, and converted to work in screen space. There are two versions, the first simply creates a BufferedImage and displays it in a JFrame. The second version uses a shader created from the first version’s code.

Simple (and slow) BufferedImage implementation of “Practical Analytic Model for Daylight”
https://docs.google.com/folder/d/0Bw97A7hoqbmPcGpVNEd6UnprSms/edit

Libgdx based shader implementation
https://docs.google.com/folder/d/0Bw97A7hoqbmPcGpVNEd6UnprSms/edit

One thing I do need a bit of help with, is that the Android version of the Libgdx shader code displays strange colours as the sun is setting. It seems to not be including any green in the colour output from the fragment shader. When the sun is high in the sky, everything looks normal, just as the sun nears the bottom of the screen it turns to purple and then dark blue.

Cheers,
Brett

Edit:
Edited links to point to zips of code

Being able to grab an archive of the source would make things easier. I’m clueless about OGL-ES, android & libgdx.

Howdy,

I updated the links to point to a folder with zips of the code.

After a little investigation, I think I have narrowed down the Android sunset colour problem to the function converting HSV back to RGB. If that step is taken out, the colours displayed on the desktop and the mobile are basically identical. I don’t know if its the float precision, or maybe something to do with casts since that is the only function with casts in the frag shader.

Another thing I am pondering, is why in the simple render to BufferedImage version, the bottom of the screen renders in light colours (as it should) while in both desktop and mobile shader versions a grey band is rendered.

Anyway, any pointers anyone might have for things that I missed in the conversion to shaders, slight mathematical differences or shader gotchas, would be appreciated.

Cheers,
Brett

Again I’m clueless about this stuff, but you could try injecting precision hints for ES to see if that addresses the issue.

Found a different HSV to/from RGB conversion algorithm here which fixed the purple sunsets on the mobile. All I can think is that the GLSL compiler on the mobile didn’t like the branching or something in the old version.

The problem of the grey band at the bottom of the screen still persists, but it is a minor issue now.

The atmosphere_libgdx.zip at the PAMD link in the first post contains the updated shader project.

Cheers,
Brett

The HSV/HSB color space is not very well defined. Particualrly in the most common implementations color of the same volume/brightness are not appearing equally bright to a human eye.

But eventually unless you doa scientific application (e.g. if you just do it to get a nice garphical effect for another project) you can always tweak the conversion till you get pleasant results.

Personally I prefer YUV to HSB becuase it has better “equal” luminance values, and you get something similar to hue by the combining the u and v vectors.

I’ve downloaded the code, but I was too distracted with other things yet to dig into it.

Now that the code is working, I might try some other colour space conversions to see if it simplifies the shader.

After posting the updated code last night, I figured out what was causing the grey band at the bottom of the screen. In the BufferedImage version, I am faking the distance of the ‘vertices’ used to draw the sky, however, in the shader version it is using an orthographic projection where vertices are close to the camera. Having the vertices this close causes an issue with lerp-ing the overcast sky factor into the sky colour. Removing the lerp made the sky show with correct colours.

Cheers,
Brett

I’ll try to motive myself (and find time) to toss together some minimalistic scattering example.

Some thoughts (don’t quote me on any of these) from quickly skimming the shader and not thinking too much:

  1. The exp’s in the Perez function are probably on limited ranges and could be replaced by a min-max approximation
  2. The whole HSV part appears to be some kind of tone mapping (I haven’t re-reviewed the paper) and could probably be replaced…seems like that gamma correction could/would be folding into the tone mapping.
  3. acos & cos of ‘gamma’ should be undroppable.

Hi bjgil2,

Very sorry to post in an older topic, I have been working for sometime on a project with procedural planets and wanted to take a look at the code you provided at the start of this topic.
Unfortunately when I run the example I get no errors, just a blank screen, I’ve had a couple of run through and did some investigating and it appears that both shaders are being compiled and
added to the program with no errors.

My opengl version is 3.1 and the shader version is 1.4.

Any chance you might know what’s going on? Regardless, thanks for taking the time to read!

Hi bjgil2,

Very sorry to post in an older topic, I have been working for sometime on a project with procedural planets and wanted to take a look at the code you provided at the start of this topic.
Unfortunately when I run the example I get no errors, just a blank screen, I’ve had a couple of run through and did some investigating and it appears that both shaders are being compiled and
added to the program with no errors.

My opengl version is 3.1 and the shader version is 1.4.

Any chance you might know what’s going on? Regardless, thanks for taking the time to read!