• 08-06-2006
VirtualAce
I need some help from you math gurus out there. These sky scatter shader formulas were taken from a GDC conference and I'm not sure how to implement the math portion.

Namely the e^-(B.R+B.M)s.

B.R is Rayleigh scattering and B.M is Mie scattering.

I can compute B.R and B.M rather easily. They are a function of a constant and an angle. Essentially the constant changes as the angle changes as well as optical length and other factors.

Computing L(in) which is in-scattering, however, looks quite complex.

Computing F(ex) which is extinction also has the e raised to -(B.R+B.M)s. How do i represent this in code? Is it

Code:

`float value=exp(-(DoRayleigh())+(DoMie())*s);`
• 08-08-2006
Sang-drax
Quote:

Originally Posted by Bubba
How do i represent this in code? Is it
Code:

`float value=exp(-(DoRayleigh())+(DoMie())*s);`

Yes, that's correct.

PS: What is E_sun?
• 08-08-2006
VirtualAce
A 4d vector representing the tri-stimulus values of sun emissivity. Lots of big wordies there but I dunno how else to explain it.

I found the source for a good shader in a Master's thesis and I'm going to tinker with it and figure it out. So far I was close, except that the GDC powerpoint did not explain which items were vectors and which one's were not. Usually vectors are upper case letters, but ya never know.

Also the GDC version assumes:

1. Low camera level - as in FPS
2. Constant atmospheric density.
3. Constant particle size.

This one I found actually simulates the first 2. The good thing about this is when I change the sun angle, the horizon will have the correct RGB values - no hacks or anything - just pure math.
• 08-21-2006
VirtualAce
Well here is an update on the sky scattering shader. After attempting to get everyone else's implementation working, I ran through the GDC article again and just coded the shader myself.

I'm quite happy with it so far. Here is a screenshot of it in action.

The trees have been disabled in this shot because I don't want to apply diffuse shading to the trees and so to apply the sky scatter shader w/o diffuse is going to require a bit more work.
• 08-21-2006
sand_man
very impressive ;)
well done
• 08-21-2006
VirtualAce
Thanks. I guess in the end copying other people's code gets you nowhere fast. I just thought I'd trust them since they knew more, but eventually my own code got it working.

Other people were using vectors to hold values used in the equations and were not using the vector as a vector per se. Good idea but very obfuscated when a noob like me is attempting to learn the stuff.

Next up is procedural texturing. I'm looking at several sources and deciding on whether or not to use octaves of Perlin noise or some other noise functions.

A very interesting link to some cool noise effects:

http://www.noisemachine.com/talk1/index.html

This is the final effect file for the sky scattering shader. Diffuse lighting is computed in this shader but I'm going to move it to another shader as well as specular.

If I change the turbidity of the atmosphere and the directional quality of the light (scattered or focused) I will get a very bright spot on the terrain where the sun would be. Using the same shader on a skydome I would then be able to simulate a very bright sun w/o using any billboards and it would look much better.
• 08-22-2006
cboard_member
>> I guess in the end copying other people's code gets you nowhere fast. I just thought I'd trust them since they knew more, but eventually my own code got it working.

That one crept up on me too. I figured that "hey now I've got this book full of examples I'll just copy most of it and it'll give me a good headstart"... Um, nope, no sale!

At first I was more reorganising than rewriting the examples but eventually I realised that I didn't fully understand some parts of it or just didn't like the way they worked at all - coding my own from scratch certainly paid off.

Anyways the shader's looking neat, man :)
• 08-23-2006
VirtualAce
The shader has some problems. Namely the directional component seems to have no effect on the color and yet it should.

The source:

Code:

```//Not used //static const float log2_e = 1.0f/log(2.0f); //Eye position float4 vEye; //Sun direction float4 vSunDirection; //Henyey/Greenstein phase function eccentricity approx float fHG; //Sun angle float fSunTheta; //Rayleigh coef float4 vBetaRayleigh; //Mie coef float4 vBetaMie; //Rayleigh+Mie coefs added float4 vBetaRM; //Sun color and intensity float4 vSunIntensity; //Diffuse color and intensity - (diffuse * intensity) component-wise multiply float4 vDIC; //Matrices float4x4 matWorldView; float4x4 matWorldViewProj; float4x4 matWorld; //Samplers sampler Terrain;  //0 sampler Detail;    //1 //Input Struct struct SkyInput {   float3 Position : POSITION;   float3 Normal : NORMAL;   float2 TerrainUV: TEXCOORD0;   float2 DetailUV:TEXCOORD1; }; //Vertex shader output struct struct VS_OUTPUT {   float4 Position : POSITION;   float3 Normal : TEXCOORD0;   float2 TerrainUV : TEXCOORD1;   float2 DetailUV: TEXCOORD2;   float4 Extinction : COLOR0;   float4 InScatter : COLOR1; }; //Compute rayleigh scattering float4 DoRayleigh(float theta) {   //(3/16)*PI   float PI316=3.0f/(16.0f*3.141592f);     //(1+(cos(theta)^2))   float theta2=theta*theta;   return vBetaRayleigh*(1.0f+theta2)*PI316; } //Compute Mie scattering float4 DoMie(float theta) {   //1/4*PI   float PI14=1.0f/(4*3.141592);       float4 fHG2=fHG*fHG;   float4 numerator=(1-fHG)*(1-fHG);   float4 denom=pow(1+fHG2-2*fHG*theta,3.0/2.0);   return (numerator/denom)*vBetaMie*PI14; } //Compute extinction float4 DoExtinction(float s) {   float4 temp=exp(-vBetaRM*s);   return temp; }   //Compute inscattering float4 DoInscatter(float theta,float4 vExtinction) {   float4 vBetaDashRM=DoRayleigh(theta)+DoMie(theta);   float4 vValue1=vBetaDashRM/vBetaRM;     return vValue1*vSunIntensity*(1.0-vExtinction); } //Vertex shader main VS_OUTPUT MainVS(SkyInput IN) {   VS_OUTPUT outParams=(VS_OUTPUT)0;      //Convert IN.Position to D3DXVECTOR4   float4 vPos=float4(IN.Position,1.0f);     //Vertex position transform   outParams.Position=mul(vPos,matWorldViewProj);     //View position   float4 ViewPos=mul(vPos,matWorldView);     //World position   float4 vWorldPos=mul(vPos,matWorld);     //Normalize the normal passed to vertex shader   float4 norm=float4(IN.Normal,1.0f);   norm=normalize(norm);     //Cosing of angle between sun and surface normal   float theta=dot(norm,vSunDirection);       //Just pass terrain u,v tex coords onto pixel shader   outParams.TerrainUV=IN.TerrainUV;     //Check for distance - no need for detail texture at large Z distances   //Only works on cards that support Pixel shader 3.0   //If we pass on detail tex coords, the pixel shader will use them   //If we don't pass them on, we effectively turn off the detail texture   //ViewPos has been correctly transformed so that Z comparisons are very simple   if (ViewPos.z<1000)   {         outParams.DetailUV=IN.DetailUV;   }            //Pass normal to pixel shader   outParams.Normal=IN.Normal;     //Compute extinction and pass to pixel shader   outParams.Extinction=DoExtinction(ViewPos.z);     //Compute inscatter and pass to pixel shader   outParams.InScatter=DoInscatter(theta,outParams.Extinction);     //Pass entire structure to pixel shader   return outParams; } //Pixel shader main float4 MainPS(VS_OUTPUT IN):COLOR {   //Get texture colors   float4 LandColor=tex2D(Terrain,IN.TerrainUV);   float4 DetailColor=tex2D(Detail,IN.DetailUV);     //Normalize normal   float3 Normal=normalize(IN.Normal);     //Compute diffuse lighting coefficient   float DiffCoef=dot(Normal,vSunDirection);     //Modulate land and detail textures   float4 MixColor=(LandColor*DetailColor);     //Compute final diffuse color and intensity   float4 Diffuse=DiffCoef*vDIC;     //Final land color is terrain mix color modulated with diffuse   float4 FinalLandColor=MixColor*Diffuse;     //Ensure alphas are 1   FinalLandColor.a=1;     //Now apply scattering   //L(s,theta)=(StartColor*Extinction(dist))+InScatter(dist,theta)   float4 FinalColor=(FinalLandColor*IN.Extinction)+IN.InScatter;     //Ensure alphas are 1   FinalColor.a=1;     //Finally we are done with this mess   return FinalColor;   } //Techniques technique SkyScatter30 {     //3.0 VS/PS pass     //Only works on pixel and vertex shader model 3.0     pass P0     {       VertexShader=compile vs_3_0 MainVS();       PixelShader=compile ps_3_0 MainPS();     } }```
The only change I'm going to make is the detail texturing. I'll gradually blend it out using alpha instead of just turning it off or on.
• 08-24-2006
BobMcGee123
I may have found some potential problems. The equations you've implemented are not the same as what you said they should be in some of your comments, in particular the DoRayleigh func:

Quote:

//(3/16)*PI
float PI316=3.0f/(16.0f*3.141592f);
(3/16)*PI is not the same as what you've assigned to PI316

and in the second part of dorayleigh:

Quote:

//(1+(cos(theta)^2))
float theta2=theta*theta;
return vBetaRayleigh*(1.0f+theta2)*PI316;
1 + cos(theta) ^ 2, or 1 + cos(theta^2)? [I don't see a cos in there to begin with, is that an approximation to cos?]

What exactly is a 'technique' supposed to be? Is that just how you compile the frag/vert programs?

Looks very good on the whole, keep up the good work!
• 08-24-2006
VirtualAce
Quote:

(3/16)*PI is not the same as what you've assigned to PI316
Even though my comment says (3/16)PI it is actually (3/16PI).

Quote:

1 + cos(theta) ^ 2, or 1 + cos(theta^2)?
Theta in my example is the dot product between the normal and the sun or light vector.