1
- // Usage: Windows / Rendering / Lighting Settings -> Environment / Skybox Material
2
- // Original reference:
3
- // https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/simulating-sky/simulating-colors-of-the-sky
4
-
5
- Shader "Atmospheric Scattering"
6
- {
7
- Properties
8
- {
9
- _Height( "Sun Altitude" ,Range (-5.0 ,5.0 )) = 0.15
10
- _Intensity ( "Sun Intensity" ,Range (1.0 ,40.0 )) = 20.0
11
- _Rayleigh ( "Rayleigh Scale" ,Range (10.0 ,10000.0 )) = 8000.0
12
- _Mie ( "Mie Scale" ,Range (10.0 ,5000.0 )) = 1200.0
13
- _Exposure( "Exposure" ,Range (10.0 ,100.0 )) = 60.0
14
- }
15
- Subshader
16
- {
17
- Tags { "RenderType" = "Background" }
18
- Pass
19
- {
20
- CGPROGRAM
21
- #pragma vertex VSMain
22
- #pragma fragment PSMain
23
- #pragma target 5.0
24
-
25
- float _Height, _Intensity, _Rayleigh, _Mie, _Exposure;
26
- static const float PI = 3.14159265358979323846 ;
27
- static const float PI_2 = 1.57079632679489661923 ;
28
- static const float PI_4 = 0.785398163397448309616 ;
29
- static const int VIEWDIR_SAMPLES = 12 ;
30
- static const int SUNDIR_SAMPLES = 8 ;
31
-
32
- bool intersect (float3 ro, float3 rd, float ra, float rs, out float tr)
33
- {
34
- float c = length (ro);
35
- float beta = PI - acos (dot (rd, ro / c));
36
- float sb = sin (beta);
37
- float b = ra;
38
- float bt = rs - 10.0 ;
39
- tr = sqrt ((b * b) - (c * c) * (sb * sb)) + c * cos (beta);
40
- if (sqrt ((bt * bt) - (c * c) * (sb * sb)) + c * cos (beta) > 0.0 ) return false ;
41
- return true ;
42
- }
43
-
44
- float visibility (float diameter, float alt)
45
- {
46
- float vap = 0.0 , h = 0.0 , a = 0.0 ;
47
- float p = clamp ((0.5 + alt / diameter), 0.0 , 1.0 );
48
- if (p == 0.0 )
49
- {
50
- return 0.0 ;
51
- }
52
- else if (p == 1.0 )
53
- {
54
- return 1.0 ;
55
- }
56
- bool sup = false ;
57
- if (p > 0.5 )
58
- {
59
- sup = true ;
60
- h = (p - 0.5 ) * 2.0 ;
61
- }
62
- else
63
- {
64
- sup = false ;
65
- h = (0.5 - p) * 2.0 ;
66
- }
67
- float alpha = acos (h) * 2.0 ;
68
- a = (alpha - sin (alpha)) / (2.0 * PI);
69
- vap = (sup) ? 1.0 - a : a;
70
- return vap;
71
- }
72
-
73
- void VSMain (inout float4 Vertex:POSITION , out float3 Point:TEXCOORD0 )
74
- {
75
- Point = mul (unity_ObjectToWorld , Vertex); // World Space coordinates
76
- Vertex = UnityObjectToClipPos (Vertex); // Screen Space coordinates
77
- }
78
-
79
- void PSMain (float4 Vertex:POSITION , float3 Point:TEXCOORD0 , out float4 fragColor:SV_TARGET )
80
- {
81
- float3 c = float3 (0.0 ,0.0 ,0.0 );
82
- float rs = 6360. 0e3; // Planet sea level radius
83
- float ra = 6420. 0e3; // Planet atmosphere radius
84
- float3 rsc = float3 (5. 5e-6 , 13. 0e-6 , 22. 1e-6 ); // Rayleigh scattering coefs at sea level
85
- float3 msc = float3 (21. 0e-6 , 21. 0e-6 , 21. 0e-6 ); // Mie scattering coefs at sea level
86
- float mean = 0.76 ; // mean cosine
87
- float azimuth = 5.0 ; // azimuth
88
- float diameter = 0.53 ; // angular diameter (between 0.5244 and 5.422 for sun)
89
- float3 ro = _WorldSpaceCameraPos .xyz + float3 (0.0 , rs + 1.0 , 0.0 );
90
- float3 rd = normalize (Point - _WorldSpaceCameraPos .xyz);
91
- float s = 0.0 ;
92
- if (!intersect (ro, rd, ra, rs, s) || s < 0.0 )
93
- c = float3 (0.0 ,0.0 ,0.0 );
94
- float sl = s / float (VIEWDIR_SAMPLES);
95
- float t = 0.0 ;
96
- float calt = cos (_Height);
97
- float3 direction = float3 (cos (azimuth) * calt, sin (_Height), sin (azimuth) * calt);
98
- float mu = dot (rd, direction);
99
- float mu2 = mu * mu;
100
- float mc2 = mean * mean;
101
- float3 sumr = float3 (0.0 ,0.0 ,0.0 );
102
- float odr = 0.0 ;
103
- float phaseR = (3.0 / (16.0 * PI)) * (1.0 + mu2);
104
- float3 summ = float3 (0.0 ,0.0 ,0.0 );
105
- float odm = 0.0 ;
106
- float phaseM = ((3.0 /(8.0 *PI))*((1.0 -mc2)*(1.0 + mu2)))/((2.0 +mc2)*pow (1.0 +mc2-2.0 *mean*mu,1.5 ));
107
- for (int i = 0 ; i < VIEWDIR_SAMPLES; ++i)
108
- {
109
- float3 sp = ro + rd * (t + 0.5 * sl);
110
- float h = length (sp) - rs;
111
- float hr = exp (-h / _Rayleigh) * sl;
112
- odr += hr;
113
- float hm = exp (-h / _Mie) * sl;
114
- odm += hm;
115
- float tm;
116
- float sp_alt = PI_2 - asin (rs / length (sp));
117
- sp_alt += acos (normalize (sp).y) + _Height;
118
- float coef = visibility (diameter, sp_alt);
119
- if (intersect (sp, direction, ra, rs, tm) || coef > 0.0 )
120
- {
121
- float sll = tm / float (SUNDIR_SAMPLES);
122
- float tl = 0.0 ;
123
- float odlr = 0.0 , odlm = 0.0 ;
124
- for (int j = 0 ; j < SUNDIR_SAMPLES; ++j)
125
- {
126
- float3 spl = sp + direction * (tl + 0.5 * sll);
127
- float spl_alt = PI_2 - asin (rs / length (spl));
128
- spl_alt += acos (normalize (spl).y) + _Height;
129
- float coefl = visibility (diameter, spl_alt);
130
- float hl = length (spl) - rs;
131
- odlr += exp (-hl / _Rayleigh) * sll * (1.0 - log (coefl + 0.000001 ));
132
- odlm += exp (-hl / _Mie) * sll * (1.0 - log (coefl + 0.000001 ));
133
- tl += sll;
134
- }
135
- float3 tau = rsc * (odr + odlr) + msc * 1.05 * (odm + odlm);
136
- float3 attenuation = float3 (exp (-tau.x), exp (-tau.y), exp (-tau.z));
137
- sumr += hr * attenuation * coef;
138
- summ += hm * attenuation * coef;
139
- }
140
- t += sl;
141
- }
142
- c = _Intensity * (sumr * phaseR * rsc + summ * phaseM * msc);
143
- c = log2 (1.0 + c * _Exposure);
144
- c = smoothstep (0.6 , 7.8 , c);
145
- c = c * c * c * (c * (c * 6.0 - 15.0 ) + 10.0 );
146
- fragColor = float4 (c, 1.0 );
147
- }
148
- ENDCG
149
- }
150
- }
151
- }
1
+ // Usage: Windows / Rendering / Lighting Settings -> Environment / Skybox Material
2
+ // Original reference:
3
+ // https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/simulating-sky/simulating-colors-of-the-sky
4
+
5
+ Shader "Atmospheric Scattering"
6
+ {
7
+ Properties
8
+ {
9
+ _Height( "Sun Altitude" ,Range (-5.0 ,5.0 )) = 0.15
10
+ _Intensity ( "Sun Intensity" ,Range (1.0 ,40.0 )) = 20.0
11
+ _Rayleigh ( "Rayleigh Scale" ,Range (10.0 ,10000.0 )) = 8000.0
12
+ _Mie ( "Mie Scale" ,Range (10.0 ,5000.0 )) = 1200.0
13
+ _Exposure( "Exposure" ,Range (10.0 ,100.0 )) = 60.0
14
+ }
15
+ Subshader
16
+ {
17
+ Tags { "RenderType" = "Background" }
18
+ Pass
19
+ {
20
+ CGPROGRAM
21
+ #pragma vertex VSMain
22
+ #pragma fragment PSMain
23
+ #pragma target 5.0
24
+
25
+ float _Height, _Intensity, _Rayleigh, _Mie, _Exposure;
26
+ static const float PI = 3.14159265358979323846 ;
27
+ static const float PI_2 = 1.57079632679489661923 ;
28
+ static const float PI_4 = 0.785398163397448309616 ;
29
+ static const int VIEWDIR_SAMPLES = 12 ;
30
+ static const int SUNDIR_SAMPLES = 8 ;
31
+
32
+ bool intersect (float3 ro, float3 rd, float ra, float rs, out float tr)
33
+ {
34
+ float c = length (ro);
35
+ float beta = PI - acos (dot (rd, ro / c));
36
+ float sb = sin (beta);
37
+ float b = ra;
38
+ float bt = rs - 10.0 ;
39
+ tr = sqrt ((b * b) - (c * c) * (sb * sb)) + c * cos (beta);
40
+ if (sqrt ((bt * bt) - (c * c) * (sb * sb)) + c * cos (beta) > 0.0 ) return false ;
41
+ return true ;
42
+ }
43
+
44
+ float visibility (float diameter, float alt)
45
+ {
46
+ float vap = 0.0 , h = 0.0 , a = 0.0 ;
47
+ float p = clamp ((0.5 + alt / diameter), 0.0 , 1.0 );
48
+ if (p == 0.0 )
49
+ {
50
+ return 0.0 ;
51
+ }
52
+ else if (p == 1.0 )
53
+ {
54
+ return 1.0 ;
55
+ }
56
+ bool sup = false ;
57
+ if (p > 0.5 )
58
+ {
59
+ sup = true ;
60
+ h = (p - 0.5 ) * 2.0 ;
61
+ }
62
+ else
63
+ {
64
+ sup = false ;
65
+ h = (0.5 - p) * 2.0 ;
66
+ }
67
+ float alpha = acos (h) * 2.0 ;
68
+ a = (alpha - sin (alpha)) / (2.0 * PI);
69
+ vap = (sup) ? 1.0 - a : a;
70
+ return vap;
71
+ }
72
+
73
+ void VSMain (inout float4 Vertex:POSITION , out float3 Point:TEXCOORD0 )
74
+ {
75
+ Point = mul (unity_ObjectToWorld , Vertex); // World Space coordinates
76
+ Vertex = UnityObjectToClipPos (Vertex); // Screen Space coordinates
77
+ }
78
+
79
+ void PSMain (float4 Vertex:POSITION , float3 Point:TEXCOORD0 , out float4 fragColor:SV_TARGET )
80
+ {
81
+ float3 c = float3 (0.0 ,0.0 ,0.0 );
82
+ float rs = 6360. 0e3; // Planet sea level radius
83
+ float ra = 6420. 0e3; // Planet atmosphere radius
84
+ float3 rsc = float3 (5. 5e-6 , 13. 0e-6 , 22. 1e-6 ); // Rayleigh scattering coefs at sea level
85
+ float3 msc = float3 (21. 0e-6 , 21. 0e-6 , 21. 0e-6 ); // Mie scattering coefs at sea level
86
+ float mean = 0.76 ; // mean cosine
87
+ float azimuth = 5.0 ; // azimuth
88
+ float diameter = 0.53 ; // angular diameter (between 0.5244 and 5.422 for sun)
89
+ float3 ro = _WorldSpaceCameraPos .xyz + float3 (0.0 , rs + 1.0 , 0.0 );
90
+ float3 rd = normalize (Point - _WorldSpaceCameraPos .xyz);
91
+ float s = 0.0 ;
92
+ if (!intersect (ro, rd, ra, rs, s) || s < 0.0 )
93
+ c = float3 (0.0 ,0.0 ,0.0 );
94
+ float sl = s / float (VIEWDIR_SAMPLES);
95
+ float t = 0.0 ;
96
+ float calt = cos (_Height);
97
+ float3 direction = float3 (cos (azimuth) * calt, sin (_Height), sin (azimuth) * calt);
98
+ float mu = dot (rd, direction);
99
+ float mu2 = mu * mu;
100
+ float mc2 = mean * mean;
101
+ float3 sumr = float3 (0.0 ,0.0 ,0.0 );
102
+ float odr = 0.0 ;
103
+ float phaseR = (3.0 / (16.0 * PI)) * (1.0 + mu2);
104
+ float3 summ = float3 (0.0 ,0.0 ,0.0 );
105
+ float odm = 0.0 ;
106
+ float phaseM = ((3.0 /(8.0 *PI))*((1.0 -mc2)*(1.0 + mu2)))/((2.0 +mc2)*pow (1.0 +mc2-2.0 *mean*mu,1.5 ));
107
+ for (int i = 0 ; i < VIEWDIR_SAMPLES; ++i)
108
+ {
109
+ float3 sp = ro + rd * (t + 0.5 * sl);
110
+ float h = length (sp) - rs;
111
+ float hr = exp (-h / _Rayleigh) * sl;
112
+ odr += hr;
113
+ float hm = exp (-h / _Mie) * sl;
114
+ odm += hm;
115
+ float tm;
116
+ float sp_alt = PI_2 - asin (rs / length (sp));
117
+ sp_alt += acos (normalize (sp).y) + _Height;
118
+ float coef = visibility (diameter, sp_alt);
119
+ if (intersect (sp, direction, ra, rs, tm) || coef > 0.0 )
120
+ {
121
+ float sll = tm / float (SUNDIR_SAMPLES);
122
+ float tl = 0.0 ;
123
+ float odlr = 0.0 , odlm = 0.0 ;
124
+ for (int j = 0 ; j < SUNDIR_SAMPLES; ++j)
125
+ {
126
+ float3 spl = sp + direction * (tl + 0.5 * sll);
127
+ float spl_alt = PI_2 - asin (rs / length (spl));
128
+ spl_alt += acos (normalize (spl).y) + _Height;
129
+ float coefl = visibility (diameter, spl_alt);
130
+ float hl = length (spl) - rs;
131
+ odlr += exp (-hl / _Rayleigh) * sll * (1.0 - log (coefl + 0.000001 ));
132
+ odlm += exp (-hl / _Mie) * sll * (1.0 - log (coefl + 0.000001 ));
133
+ tl += sll;
134
+ }
135
+ float3 tau = rsc * (odr + odlr) + msc * 1.05 * (odm + odlm);
136
+ float3 attenuation = float3 (exp (-tau.x), exp (-tau.y), exp (-tau.z));
137
+ sumr += hr * attenuation * coef;
138
+ summ += hm * attenuation * coef;
139
+ }
140
+ t += sl;
141
+ }
142
+ c = _Intensity * (sumr * phaseR * rsc + summ * phaseM * msc);
143
+ c = log2 (1.0 + c * _Exposure);
144
+ c = smoothstep (0.6 , 7.8 , c);
145
+ c = c * c * c * (c * (c * 6.0 - 15.0 ) + 10.0 );
146
+ fragColor = float4 (c, 1.0 );
147
+ }
148
+ ENDCG
149
+ }
150
+ }
151
+ }
0 commit comments