1 struct AtmosphericEvents
11 AtmosphericEvents events;
12 float rayleigh_density_decay;
13 float mie_density_decay;
14 float ozone_band_center;
15 float ozone_band_extent;
17 float atmosphere_thickness;
29 struct OpticalPathInfo
35 const float mie_asymmetry = 0.8;
37 uniform sampler2D transmittance_lookup;
39 vec3 rayleigh_density(vec3 base, float height)
41 return base*exp(height/rayleigh_density_decay);
44 float rayleigh_phase(float cos_theta)
46 return 3.0*(1.0+cos_theta*cos_theta)/(16.0*PI);
49 vec3 mie_density(vec3 base, float height)
51 return base*exp(height/mie_density_decay);
54 float mie_phase(float cos_theta)
56 float g = mie_asymmetry;
57 float num = (1.0-g*g)*(1.0+cos_theta*cos_theta);
58 float denom = (2.0+g*g)*pow(1.0+g*g-2.0*g*cos_theta, 1.5);
59 return 3.0/(8.0*PI)*num/denom;
62 vec3 ozone_density(vec3 base, float height)
64 return base*max(1.0-abs(height-ozone_band_center)/ozone_band_extent, 0.0);
67 AtmosphericEvents calculate_events(float height)
70 ev.rayleigh_scatter = rayleigh_density(events.rayleigh_scatter, height);
71 ev.mie_scatter = mie_density(events.mie_scatter, height);
72 ev.mie_absorb = mie_density(events.mie_absorb, height);
73 ev.ozone_absorb = ozone_density(events.ozone_absorb, height);
77 vec3 total_extinction(AtmosphericEvents ev)
79 return ev.rayleigh_scatter+ev.mie_scatter+ev.mie_absorb+ev.ozone_absorb;
82 float ray_sphere_intersect(vec3 ray_start, vec3 ray_dir, vec3 sphere_center, float sphere_radius)
84 float t = dot(sphere_center-ray_start, ray_dir);
85 vec3 nearest = ray_start+t*ray_dir-sphere_center;
86 float d_sq = dot(nearest, nearest);
87 float r_sq = sphere_radius*sphere_radius;
91 float offset = sqrt(r_sq-d_sq);
100 #pragma MSP stage(fragment)
101 OpticalPathInfo raymarch_path(float start_height, vec3 look_dir)
103 float cos_theta = dot(look_dir, light_dir);
104 float p_rayleigh = rayleigh_phase(cos_theta);
105 float p_mie = mie_phase(cos_theta);
107 vec3 planet_center = vec3(0.0, 0.0, -planet_radius);
108 vec3 pos = vec3(0.0, 0.0, start_height);
109 vec3 path_luminance = vec3(0.0);
110 vec3 path_extinction = vec3(0.0);
112 float ground_t = ray_sphere_intersect(pos, look_dir, planet_center, planet_radius);
113 float space_t = ray_sphere_intersect(pos, look_dir, planet_center, planet_radius+atmosphere_thickness);
114 float ray_length = (ground_t>0.0 ? ground_t : space_t);
115 float step_size = ray_length/n_steps;
117 for(int i=0; i<=n_steps; ++i)
119 vec3 from_center = pos-planet_center;
120 float height = length(from_center);
121 float light_z = dot(from_center/height, light_dir);
122 height -= planet_radius;
124 AtmosphericEvents ev = calculate_events(height);
125 vec3 transmittance = exp(-path_extinction);
126 vec3 in_transmittance = texture(transmittance_lookup, vec2(sqrt(height/atmosphere_thickness), light_z)).rgb;
127 vec3 in_luminance = (ev.rayleigh_scatter*p_rayleigh+ev.mie_scatter*p_mie)*step_size;
128 if(i==n_steps && ground_t>0.0)
129 in_luminance += ground_albedo*light_z/PI;
130 path_luminance += transmittance*in_transmittance*in_luminance;
132 path_extinction += total_extinction(ev)*step_size;
133 pos += look_dir*step_size;
136 return OpticalPathInfo(path_extinction, path_luminance);