summaryrefslogtreecommitdiffstats
path: root/Shaders/PostProcess/EpipolarLightScattering/private/Extinction.fxh
blob: 6b09faec700c7bc803525e3ec9465dc5adadfe3a (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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// This function for analytical evaluation of particle density integral is 
// provided by Eric Bruneton
// http://www-evasion.inrialpes.fr/Membres/Eric.Bruneton/
//
// optical depth for ray (r,mu) of length d, using analytic formula
// (mu=cos(view zenith angle)), intersections with ground ignored
float2 GetDensityIntegralAnalytic(float r, float mu, float d, float EarthRadius, float4 ParticleScaleHeight) 
{
    float2 f2A     = sqrt(ParticleScaleHeight.zw * 0.5 * r);
    float4 f4A01   = f2A.xxyy * float2(mu, mu + d / r).xyxy;
    float4 f4A01s  = sign(f4A01);
    float4 f4A01sq = f4A01 * f4A01;
    
    float2 f2X;
    f2X.x = f4A01s.y > f4A01s.x ? exp(f4A01sq.x) : 0.0;
    f2X.y = f4A01s.w > f4A01s.z ? exp(f4A01sq.z) : 0.0;
    
    float4 f4Y =
        f4A01s 
        / (2.3193 * abs(f4A01) + sqrt(1.52 * f4A01sq + 4.0)) 
        * float3(1.0, exp(-ParticleScaleHeight.zw * d * (d / (2.0 * r) + mu)) ).xyxz;

    return 
        sqrt((6.2831 * ParticleScaleHeight.xy) * r) 
        * exp((EarthRadius - r) * ParticleScaleHeight.zw) 
        * (f2X + float2(f4Y.x - f4Y.y, f4Y.z - f4Y.w));
}


float3 GetExtinctionUnverified(float3 f3StartPos,
                               float3 f3EndPos,
                               float3 f3EyeDir,
                               float3 f3EarthCentre,
                               float  fEarthRadius,
                               float4 f4ParticleScaleHeight)
{
#if 0
    float2 f2ParticleDensity = IntegrateParticleDensity(f3StartPos, f3EndPos, f3EarthCentre, 20);
#else
    float r = length(f3StartPos-f3EarthCentre);
    float fCosZenithAngle = dot(f3StartPos-f3EarthCentre, f3EyeDir) / r;
    float2 f2ParticleDensity = GetDensityIntegralAnalytic(r, fCosZenithAngle, length(f3StartPos - f3EndPos), fEarthRadius, f4ParticleScaleHeight);
#endif

    // Get optical depth
    float3 f3TotalRlghOpticalDepth = g_MediaParams.f4RayleighExtinctionCoeff.rgb * f2ParticleDensity.x;
    float3 f3TotalMieOpticalDepth  = g_MediaParams.f4MieExtinctionCoeff.rgb      * f2ParticleDensity.y;
        
    // Compute extinction
    float3 f3Extinction = exp( -(f3TotalRlghOpticalDepth + f3TotalMieOpticalDepth) );
    return f3Extinction;
}

float3 GetExtinction(float3 f3StartPos,
                     float3 f3EndPos,
                     float3 f3EarthCentre,
                     float  fEarthRadius,
                     float  fAtmTopRadius,
                     float4 f4ParticleScaleHeight)
{
    float3 f3EyeDir = f3EndPos - f3StartPos;
    float fRayLength = length(f3EyeDir);
    f3EyeDir /= fRayLength;

    // Compute intersections of the view ray with the atmosphere and the Earth
    float4 f4Isecs;
    GetRaySphereIntersection2( f3StartPos, f3EyeDir, f3EarthCentre,
                               float2(fEarthRadius, fAtmTopRadius), 
                               f4Isecs);
    float2 f2RayEarthIsecs  = f4Isecs.xy;
    float2 f2RayAtmTopIsecs = f4Isecs.zw;

    // If the ray misses the atmosphere, there is no extinction
    if (f2RayAtmTopIsecs.y < 0.0)
    {
        return float3(1.0, 1.0, 1.0);
    }

    // Limit the ray length by the distance to the top of the atmosphere
    fRayLength = min(fRayLength, f2RayAtmTopIsecs.y);

    if (f2RayEarthIsecs.x > 0.0)
    {
        // The ray hits the Earth surface
        fRayLength = min(fRayLength, f2RayEarthIsecs.x);
    }

    // Update the end point
    f3EndPos = f3StartPos + f3EyeDir * fRayLength;

    // If the ray starts outside of the atmosphere, move the starting point to the intersection
    f3StartPos += f3EyeDir * max(f2RayAtmTopIsecs.x, 0.0);

    return GetExtinctionUnverified(f3StartPos, f3EndPos, f3EyeDir, f3EarthCentre, fEarthRadius, f4ParticleScaleHeight);
}