forked from tordanik/OSM2World
/
sky.fragment
146 lines (113 loc) · 4.28 KB
/
sky.fragment
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* Simple fragment shader for drawing a 2d geometry with texture to screen
*/
#version 140
uniform vec3 sunVector;
uniform float sunIntensity;
uniform mat4 inv_proj;
uniform mat4 inv_view;
// How much the atmosphere scatters each channel
uniform vec3 Kr;
uniform float step_count = 10.0;
// corresponds with output from vertex shader, gets interpolated
in vec4 FragCoord;
// output to buffer
out vec4 FragColor;
// Calculates how much light is scattered in a direction where
// alpha is the angle between the original direction and the
// new direction
float phase(float alpha, float g){
float a = 3.0*(1.0-g*g);
float b = 2.0*(2.0+g*g);
float c = 1.0+alpha*alpha;
float d = pow(1.0+g*g-2.0*g*alpha, 1.5);
return (a/b)*(c/d);
}
// Calculates how far a ray at a certain altitude has to travel a certain
// direction before it leaves the atmosphere where 0 is the center of the
// earth and 1 is the edge of the atmosphere
float atmospheric_depth(float alt, vec3 dir){
float d = dir.y;
return sqrt(alt*alt * (d*d-1) + 1) - alt*d;
}
// Calculates how much light is blocked by the horizon
float horizon_extinction(vec3 position, vec3 dir, float radius){
float u = dot(dir, -position);
if(u<0.0){
return 1.0;
}
vec3 near = position + u*dir;
if(length(near) < radius){
return 0.0;
}else{
vec3 v2 = normalize(near)*radius - position;
float diff = acos(dot(normalize(v2), dir));
return smoothstep(0.0, 1.0, pow(diff*2.0, 3.0));
}
}
// color - color * Kr^(factor/distance)
vec3 extinction(float dist, vec3 color, float factor){
return color-color*pow(Kr, vec3(factor/dist));
}
void main()
{
float rayleigh_brightness = 0.7;
float mie_brightness = 1.0;
// Ratio of earth radius to radius + atmosphere
float surface_height = 0.9953;
float scatter_strength = 0.1;
// Size of mie scattering particles
float mie_distribution = 0.99995;
// Calculate the vector from the camera to the fragment
vec4 device_normal = vec4(FragCoord.xy, 0, 1.0);
vec3 eye_normal = ((inv_proj * device_normal).xyz);
vec3 eyeVector = normalize(mat3(inv_view) * eye_normal);
// Calculates a factor for each type of scattering based on the size
// of the particles and the angle between the sun and view directions
float alpha = dot(eyeVector, sunVector);
float rayleigh_phase = phase(alpha, 0.0);
float mie_phase = phase(alpha, mie_distribution);
// Calculate how big steps we should take so that there are exactly step_count
// steps between the eye and the edge of the atmosphere
vec3 eye_position = vec3(0.0, surface_height, 0.0);
float eye_depth = atmospheric_depth(eye_position.y, eyeVector.xyz);
float step_length = eye_depth / float(step_count);
vec3 rayleigh_collected = vec3(0.0, 0.0, 0.0);
vec3 mie_collected = vec3(0.0, 0.0, 0.0);
for(int i=0; i<step_count; i++){
// Calculate the sample position in worldspace
float sample_distance = step_length*float(i);
vec3 position = eye_position + eyeVector.xyz*sample_distance;
// How much light from the sun to the sample point is extincted
// by the horizon
float sun_extinction = horizon_extinction(
position, sunVector, surface_height-0.01
);
// How much of the ray cast from the eye to the sun is in the atmosphere
float sample_depth = atmospheric_depth(position.y, sunVector);
// Amount of sunlight that makes it through the atmosphere to the sample position
vec3 influx = extinction(sample_depth, vec3(sunIntensity), scatter_strength) * sun_extinction;
// Amount of light that is in-scattered due to each type of scattering and makes it through
// the atmosphere from the sample point to the viewer
rayleigh_collected += extinction(sample_distance, Kr * influx * rayleigh_phase, scatter_strength);
mie_collected += extinction(sample_distance, influx * mie_phase, scatter_strength);
}
// Calculate the horizon
float eye_extinction = horizon_extinction(
eye_position, eyeVector.xyz, surface_height - 0.01
);
// Apply the horizon and scale the result
rayleigh_collected = (
rayleigh_collected *
eye_extinction
) / step_count;
mie_collected = (
mie_collected *
eye_extinction
) / step_count;
// Calculate the final color by apply the amount of light that is inscattered
vec3 color = vec3(
mie_brightness * mie_collected +
rayleigh_brightness * rayleigh_collected
);
FragColor = vec4(color, 1.0);
}