I have swapped engines due to irrlicht's poor parallel performance, things were being held back by the CPU etc etc. causing a drop in FPS which was unnacceptable. Therefore I didnt produce any code for irrlicht (I have but a quick hack over ATMOsphere, unsuitable for redistribution because of code cleaness and performance).
This is per-pixel, and not per vertex unlike nvidia's and Ogre3D's SkyX. Therefore better
so you can take 3 samples for it to look good (I prefer

The thing is first rendered to a texture, then texture wrapped on a hemi-sphere, this is LatLong wrapping but I will work on getting the thing in Peirce Quincuncial Projection so area is preserved (there is oversampling at the top and undersampling on the rim of the hemi-sphere)
So you will have to C++ this code for yourself
However I have not left you on your own, in the shader comments there are recomended values for uniform values.
I would also build on top of "ATMOsphere by pazystamo" to get the sun vector... normalize(AbsolutecameraPos-AbsolutesunPos)
Of course you will need to get rid of ATMOsphere's billboard sun...
Shaders:
std.vert
Code: Select all
varying vec3 normal;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix *gl_Vertex;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
normal = gl_Normal;
}this shader tricks a screenQuad into "thinking" its a sphere and performs scattering
Code: Select all
// Could not be defines because they get altered
float Mie = 0.0005;
float Ray = 0.0025;
// time' contains seconds since the program was linked.
uniform float g,gSQ,altitudeMetres,atmoAltInKm,sunIntensity,Exposure;
// -0.921, g^2, x<250, 120, 50, 1.6 == reccomended values
uniform int nSamples; // 8<x<24
uniform vec3 WaveLen, sun; // (x,y,z), (0.57,0.54,0.44)
uniform sampler2D stars;
#define innerR 9.82751
#define outerR 10.2963
#define IOscale 0.46879
float scaledDepth;
float F(float cosD) {
return 0.75*cosD*cosD+0.75;
}
float FMie(float cosD) {
return ((3.0*(1.0-gSQ))/(2.0*(2.0+gSQ)))*((1.0+cosD*cosD)/pow(1.0+gSQ-2.0*g*cosD,1.5));
}
float scale(float cosd)
{
float x = 1.0 - cosd;
return scaledDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}
void main()
{
// == Dome from UV reconstr
vec3 norm;
norm.y = cos(gl_TexCoord[0].y*1.570796);
norm.x = cos(6.283184*gl_TexCoord[0].x);
norm.z = sin(6.283184*gl_TexCoord[0].x);
norm.xz *= sqrt(1.0-norm.y*norm.y);
// == Begin Scattering
vec3 sunDir = normalize(sun);
float sunToStar = 1.0+min(0.1+sunDir.y/max(abs(sunDir.x),max(abs(sunDir.y),abs(sunDir.z))),0.0);
float Ho = 1.0-pow(max(sunDir.y,0.0),0.5)*0.8;
Mie += pow(1.0-abs(sunDir.y),3.0)*0.006;
Ray += pow(1.0-abs(sunDir.y),1.25)*0.003;
scaledDepth = IOscale*Ho;
float IOscaleSQHo = pow(IOscale,2.0)*Ho;
float cameraH = (IOscale/atmoAltInKm)*altitudeMetres/1000.0;
float fDepth = exp(-cameraH/IOscaleSQHo);
vec3 vRay = norm;
vRay.y -= cameraH;
float fFar = length(vRay);
vRay /= fFar;
vec3 vStart = vec3(0.0,cameraH,0.0);
float fStartOffset = fDepth * scale(vRay.y);
float fSampleLen = fFar/float(nSamples);
float fScaledLen = fSampleLen/IOscale;
vec3 vSampleRay = vRay*fSampleLen;
vec3 vSamplePoint = vStart+vSampleRay*0.5;
vec3 invPwrRayWave = 1.0/pow(WaveLen,4.0)*Ray;
vec3 invPwrMieWave = 1.0/pow(WaveLen,0.84)*Mie;
vec3 loopWave = invPwrMieWave*12.56637+invPwrRayWave*12.56637;
// ray tracing :)
vec3 color;
for (int i = 0; i < nSamples; i++)
{
float fHeight = length(vSamplePoint);
fDepth = exp(-fHeight/IOscaleSQHo);
float fLightAngle = 0.45+0.55*dot(sunDir, vSamplePoint) / fHeight;
float fCameraAngle = 0.45+0.55*dot(vRay, vSamplePoint) / fHeight;
float fScatter = fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle));
vec3 vAttenuate = exp(-fScatter*loopWave );
// Accumulate color
color.xyz += vAttenuate*(fDepth * fScaledLen);
// Next sample point
vSamplePoint += vSampleRay;
}
vec3 RayleighColor = color*invPwrRayWave;
vec3 MieColor = color*invPwrMieWave;
float cosd = dot(normalize(vec3(0.0,cameraH,0.0)-norm),sunDir);
vec4 final = vec4(1.0-exp(-(Exposure)*(FMie(cosd)*MieColor+F(cosd)*RayleighColor)*sunIntensity*(1.0+pow(max(sunDir.y*1.25,0.0),4.0))),1.0)*pow(sunToStar,6.0);
//Stolen from SkyX
float nightmult = saturate(1 - max(final.x, max(final.y, final.z))*64);
final.xyz += nightmult *(vec3(0.02, 0.02, 0.04)*(2.0-0.75*saturate(-sunDir.y))*pow(1.0-norm.y,3.0) + texture2D(stars,normalize(vec3(norm.x,norm.y*0.85+0.15,norm.z)).xz).xyz*(0.35 + saturate(-sunDir.y*0.45)));
gl_FragColor = final;
}Code: Select all
// simple fragment shader
// 'time' contains seconds since the program was linked.
uniform sampler2D tex;
varying vec3 normal;
void main()
{
vec3 norm = normalize(normal);
vec2 normXZ = normalize(norm.xz);
float rX = (norm.z<0.0 ? (6.283183-acos(normXZ.x)):acos(normXZ.x))/6.283183;
float rY = acos(norm.y)/1.570796;
vec2 TC = vec2(rX,rY);
gl_FragColor = texture2D(tex,clamp(TC,0.005,0.996));
if (norm.y<0.0) gl_FragColor = 0.0;
}1) make a ScreenQuad (like xEffects)
2) make a shader material for that quad using the Scatter.frag and std.vert shader
3) make two Render Targets (if you are a cheapscape 512x512 will do, but I advise >=1024X1024)
4) have a function called updateTexture() which is invoked each frame
now In this function you need to update the first renderTarget, render
into it using the quad with the Scatter shader
HOWEVER THERE IS AN IMPORTANT BUT:
If you try to update a 1024*1024 texture in one go your FPS is guaranteed to drop by loads. So here is a simple trick, split the screen into n^2 cells (i.e. 64). Then each updateTexture() function call, you set the view port to a particular cell and render that fraction of the screenQuad, then move along one cell. If you had split the texture into 64 cells and had 60 FPS then the texture would be updated within 1.5 seconds. Now when you completed with updating all the cells (64 out of 64 done) you copy the texture into the second Render Target we made earlier, then start the process again. You needed that second RTT to only see the finished result, and not see the half the cells upgraded and half not. Because the sun is moving slowly (if I remember right ATMOsphere updates the sun position every 15 virtual mins) you will not notice any lags.
5) every frame draw a skydome with the LookUp.frag shader&&material !!IT MUST HAVE BILINEAR FILTERING!! (trilinear and anisotropic are even better)
If you implement according to the above, even a shitty-just-support-shader-model-2.0 5800 geforce mobile laptop chipset should get 60 fps
P.S. I am really sorry that it sounds like a speech, and that i presented irrlicht in a bad light




