1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
"#include \"AtmosphereShadersCommon.fxh\"\n"
"\n"
"\n"
"cbuffer cbParticipatingMediaScatteringParams\n"
"{\n"
" AirScatteringAttribs g_MediaParams;\n"
"}\n"
"\n"
"float2 IntegrateParticleDensity(float3 f3Start, \n"
" float3 f3End,\n"
" float3 f3EarthCentre,\n"
" int iNumSteps )\n"
"{\n"
" float3 f3Step = (f3End - f3Start) / float(iNumSteps);\n"
" float fStepLen = length(f3Step);\n"
" \n"
" float fStartHeightAboveSurface = abs( length(f3Start - f3EarthCentre) - g_MediaParams.fEarthRadius );\n"
" float2 f2PrevParticleDensity = exp( -fStartHeightAboveSurface * g_MediaParams.f4ParticleScaleHeight.zw );\n"
"\n"
" float2 f2ParticleNetDensity = float2(0.0, 0.0);\n"
" for (int iStepNum = 1; iStepNum <= iNumSteps; ++iStepNum)\n"
" {\n"
" float3 f3CurrPos = f3Start + f3Step * float(iStepNum);\n"
" float fHeightAboveSurface = abs( length(f3CurrPos - f3EarthCentre) - g_MediaParams.fEarthRadius );\n"
" float2 f2ParticleDensity = exp( -fHeightAboveSurface * g_MediaParams.f4ParticleScaleHeight.zw );\n"
" f2ParticleNetDensity += (f2ParticleDensity + f2PrevParticleDensity) * fStepLen / 2.0;\n"
" f2PrevParticleDensity = f2ParticleDensity;\n"
" }\n"
" return f2ParticleNetDensity;\n"
"}\n"
"\n"
"float2 IntegrateParticleDensityAlongRay(float3 f3Pos, \n"
" float3 f3RayDir,\n"
" float3 f3EarthCentre, \n"
" const int iNumSteps,\n"
" const bool bOccludeByEarth)\n"
"{\n"
" if( bOccludeByEarth )\n"
" {\n"
" // If the ray hits the bottom atmosphere boundary, return huge optical depth\n"
" float2 f2RayEarthIsecs; \n"
" GetRaySphereIntersection(f3Pos, f3RayDir, f3EarthCentre, g_MediaParams.fAtmBottomRadius, f2RayEarthIsecs);\n"
" if( f2RayEarthIsecs.x > 0.0 )\n"
" return float2(1e+20, 1e+20);\n"
" }\n"
"\n"
" // Get intersection with the top of the atmosphere (the start point must always be under the top of it)\n"
" // \n"
" // /\n"
" // . / . \n"
" // . \' /\\ \' .\n"
" // / f2RayAtmTopIsecs.y > 0\n"
" // *\n"
" // f2RayAtmTopIsecs.x < 0\n"
" // /\n"
" // \n"
" float2 f2RayAtmTopIsecs;\n"
" GetRaySphereIntersection(f3Pos, f3RayDir, f3EarthCentre, g_MediaParams.fAtmTopRadius, f2RayAtmTopIsecs);\n"
" float fIntegrationDist = f2RayAtmTopIsecs.y;\n"
"\n"
" float3 f3RayEnd = f3Pos + f3RayDir * fIntegrationDist;\n"
"\n"
" return IntegrateParticleDensity(f3Pos, f3RayEnd, f3EarthCentre, iNumSteps);\n"
"}\n"
"\n"
"void PrecomputeNetDensityToAtmTopPS( FullScreenTriangleVSOutput VSOut,\n"
" out float2 f2Density : SV_Target0 )\n"
"{\n"
" float2 f2UV = NormalizedDeviceXYToTexUV(VSOut.f2NormalizedXY);\n"
" // Do not allow start point be at the Earth surface and on the top of the atmosphere\n"
" float fStartHeight = clamp( lerp(g_MediaParams.fAtmBottomAltitude, g_MediaParams.fAtmTopAltitude, f2UV.x), 10.0, g_MediaParams.fAtmTopAltitude-10.0 );\n"
"\n"
" float fCosTheta = f2UV.y * 2.0 - 1.0;\n"
" float fSinTheta = sqrt( saturate(1.0 - fCosTheta*fCosTheta) );\n"
" float3 f3RayStart = float3(0.0, 0.0, fStartHeight);\n"
" float3 f3RayDir = float3(fSinTheta, 0.0, fCosTheta);\n"
" \n"
" float3 f3EarthCentre = float3(0.0, 0.0, -g_MediaParams.fEarthRadius);\n"
"\n"
" const int iNumSteps = 200;\n"
" f2Density = IntegrateParticleDensityAlongRay(f3RayStart, f3RayDir, f3EarthCentre, iNumSteps, true);\n"
"}\n"
|