summaryrefslogtreecommitdiffstats
path: root/Shaders/PostProcess/EpipolarLightScattering/private/precompute/PrecomputeNetDensityToAtmTop.fx
blob: 472909e5cdd113c959750daf29fa5ac4af0a2aec (plain)
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"


cbuffer cbParticipatingMediaScatteringParams
{
    AirScatteringAttribs g_MediaParams;
}

float2 IntegrateParticleDensity(float3 f3Start, 
                                float3 f3End,
                                float3 f3EarthCentre,
                                int    iNumSteps )
{
    float3 f3Step = (f3End - f3Start) / float(iNumSteps);
    float fStepLen = length(f3Step);
        
    float fStartHeightAboveSurface = abs( length(f3Start - f3EarthCentre) - g_MediaParams.fEarthRadius );
    float2 f2PrevParticleDensity = exp( -fStartHeightAboveSurface * g_MediaParams.f4ParticleScaleHeight.zw );

    float2 f2ParticleNetDensity = float2(0.0, 0.0);
    for (int iStepNum = 1; iStepNum <= iNumSteps; ++iStepNum)
    {
        float3 f3CurrPos = f3Start + f3Step * float(iStepNum);
        float fHeightAboveSurface = abs( length(f3CurrPos - f3EarthCentre) - g_MediaParams.fEarthRadius );
        float2 f2ParticleDensity = exp( -fHeightAboveSurface * g_MediaParams.f4ParticleScaleHeight.zw );
        f2ParticleNetDensity += (f2ParticleDensity + f2PrevParticleDensity) * fStepLen / 2.0;
        f2PrevParticleDensity = f2ParticleDensity;
    }
    return f2ParticleNetDensity;
}

float2 IntegrateParticleDensityAlongRay(float3     f3Pos, 
                                        float3     f3RayDir,
                                        float3     f3EarthCentre, 
                                        const int  iNumSteps,
                                        const bool bOccludeByEarth)
{
    if( bOccludeByEarth )
    {
        // If the ray hits the bottom atmosphere boundary, return huge optical depth
        float2 f2RayEarthIsecs; 
        GetRaySphereIntersection(f3Pos, f3RayDir, f3EarthCentre, g_MediaParams.fAtmBottomRadius, f2RayEarthIsecs);
        if( f2RayEarthIsecs.x > 0.0 )
            return float2(1e+20, 1e+20);
    }

    // Get intersection with the top of the atmosphere (the start point must always be under the top of it)
    //      
    //                     /
    //                .   /  . 
    //      .  '         /\         '  .
    //                  /  f2RayAtmTopIsecs.y > 0
    //                 *
    //                   f2RayAtmTopIsecs.x < 0
    //                  /
    //      
    float2 f2RayAtmTopIsecs;
    GetRaySphereIntersection(f3Pos, f3RayDir, f3EarthCentre, g_MediaParams.fAtmTopRadius, f2RayAtmTopIsecs);
    float fIntegrationDist = f2RayAtmTopIsecs.y;

    float3 f3RayEnd = f3Pos + f3RayDir * fIntegrationDist;

    return IntegrateParticleDensity(f3Pos, f3RayEnd, f3EarthCentre, iNumSteps);
}

void PrecomputeNetDensityToAtmTopPS( FullScreenTriangleVSOutput VSOut,
                                     out float2 f2Density : SV_Target0 )
{
    float2 f2UV = NormalizedDeviceXYToTexUV(VSOut.f2NormalizedXY);
    // Do not allow start point be at the Earth surface and on the top of the atmosphere
    float fStartHeight = clamp( lerp(g_MediaParams.fAtmBottomAltitude, g_MediaParams.fAtmTopAltitude, f2UV.x), 10.0, g_MediaParams.fAtmTopAltitude-10.0 );

    float fCosTheta = f2UV.y * 2.0 - 1.0;
    float fSinTheta = sqrt( saturate(1.0 - fCosTheta*fCosTheta) );
    float3 f3RayStart = float3(0.0, 0.0, fStartHeight);
    float3 f3RayDir = float3(fSinTheta, 0.0, fCosTheta);
    
    float3 f3EarthCentre = float3(0.0, 0.0, -g_MediaParams.fEarthRadius);

    const int iNumSteps = 200;
    f2Density = IntegrateParticleDensityAlongRay(f3RayStart, f3RayDir, f3EarthCentre, iNumSteps, true);
}