Implementing Rayleigh & Mie Scattering

I’m in the process of upgrading my Earth / Blue Marble project and want to implement a much more accurate atmospheric scattering model. In my implementation, it’s possible for the Camera to be both above and below the atmosphere (usually though, above).

My current implementation is super-simple, it’s an inverted-poly sphere slightly larger than the Earth, and uses a 1D-Texture to map colours to the atmosphere based on the Dot product of the Sunlight Vector. The effect is then pushed out to the edges and softened at the edges to give the haziness and falloff. It’s fairly cheap (and also has very little overdraw), but it doesn’t hold up at glancing angles in the way that I want it do.

I’m currently working the Rayleigh side of the GPU Gems Implementation and have the ‘Intensity’ worked out (judging by the image below), but now I’m getting lost in a haze of mathematics when it comes to sampling, and also seems to require some kind of look-up texture in order to work properly based on those samples. I know there is an Atmosphere Scattering system that implements both models coming to Marketplace (which I will get regardless of whether I do this or not), but honestly I’d quite like to learn how to do it myself before grabbing that one and having a look at it. Here’s where I’m at with the Rayleigh scattering. (Note: ArcCos is a tiny bit of HLSL). If anybody can help point me in the right direction, feel free :slight_smile:

I suggest taking a look at this newer scattering paper. Most of the math is the same, but the technique is a bit different and gives you a much higher quality result:

The authors also have a demo application if you search around, though the bits for taking into account terrain (which also get you light-shafts) are not implemented, since they’re using a totally smooth sphere.

There’s also an implementation of the GPU Gems version in the Torque 3D source code which you can look at.

That looks very interesting! I’ll check that one out as well, it certainly looks more accurate than the Mie / Rayleigh implementation. Hopefully it’s also faster, since I’ve found two version of MR, one of which requires a slow look-up-table (which I started building above but have now abandoned), and another which intends to run faster. What I like about it though is that I can feed in a refraction parameter and possibly a texture too, so I can create different scattering for the clouds in the same shader. We’ll have to see I guess.

I’m running out of instructions and cycles, so hopefully it’s nice and fast… thanks for the links!

Ah, major hitch unfortunately. The one you linked me too is precomputed only, which is no good for me since it has to work in realtime and this one takes several seconds to compute.

If anybody else has any pointers, feel free to post them here. Still struggling with this, particularly when it gets to the multiple sampling part. Might have to write my own HLSL node.

You only have to do that precompute once, though, it’s real time after that (from whatever angle - at least on the ground, in which case you can just blend between two precomps - ground and space).

Definitely check out the Bruneton demo, it has source code including the shaders.

Also you definitely need to do multiple samples, there’s no real getting around that, as that’s what’s giving the atmosphere volume. Though you can get away with reducing the number of samples a lot, though it will cause nasty artifacting in some cases. I think even 2 or 3 will work.

Ah I see, so they compute a lookup table first then go from there. I could probably make that LUT a static texture somewhere as well. I’ll have a second look.

The difficulty is figuring out how to do multiple samples in the Material Editor, since I can either have a huge duplication of nodes, or I have to use HLSL. Unfortunately the HLSL versions all seem to require calls to other functions, which prevents me from using it at all. Also means it won’t cross-compile to Android either.

I’m also working on this myself and I advise you to check this Thesis paper from Mr Stefan Sperlhofer which is based on Mr Eric Bruneton paper but goes into much more details both for theory and implementation (also with code):

You just resurrected an old topic :stuck_out_tongue: but I appreciate the link anyway.

In case you are still wondering about this, it is possible to call other custom-node functions but it can be a little annoying to setup (especially if you need to call functions that call other functions).


So in your custom node you add an input parameter for the function you are gonna call (note that the “Custom0” name doesn’t matter but the order does matter if you add multiple functions) then you call that function with CustomExpression0(Parameters, vars…)… CustomExpression1… and so on.

Also note you just need to plug zero to the Function-to-be-called.

There’s a solution on Marketplace now too.