@takram/three-clouds 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +1130 -0
- package/assets/local_weather.png +0 -0
- package/assets/shape.bin +1 -0
- package/assets/shape_detail.bin +1 -0
- package/assets/turbulence.png +0 -0
- package/build/index.cjs +583 -0
- package/build/index.cjs.map +1 -0
- package/build/index.js +728 -0
- package/build/index.js.map +1 -0
- package/build/r3f.cjs +2 -0
- package/build/r3f.cjs.map +1 -0
- package/build/r3f.js +205 -0
- package/build/r3f.js.map +1 -0
- package/build/shared.cjs +2189 -0
- package/build/shared.cjs.map +1 -0
- package/build/shared.js +3825 -0
- package/build/shared.js.map +1 -0
- package/package.json +77 -0
- package/src/CascadedShadowMaps.ts +288 -0
- package/src/CloudLayer.ts +85 -0
- package/src/CloudLayers.test.ts +61 -0
- package/src/CloudLayers.ts +181 -0
- package/src/CloudShape.ts +22 -0
- package/src/CloudShapeDetail.ts +22 -0
- package/src/CloudsEffect.ts +810 -0
- package/src/CloudsMaterial.ts +467 -0
- package/src/CloudsPass.ts +285 -0
- package/src/CloudsResolveMaterial.ts +108 -0
- package/src/DensityProfile.ts +38 -0
- package/src/LocalWeather.ts +21 -0
- package/src/PassBase.ts +28 -0
- package/src/Procedural3DTexture.ts +94 -0
- package/src/ProceduralTexture.ts +94 -0
- package/src/ShaderArrayPass.ts +32 -0
- package/src/ShadowMaterial.ts +141 -0
- package/src/ShadowPass.ts +185 -0
- package/src/ShadowResolveMaterial.ts +72 -0
- package/src/Turbulence.ts +21 -0
- package/src/bayer.ts +23 -0
- package/src/constants.ts +8 -0
- package/src/helpers/FrustumCorners.ts +138 -0
- package/src/helpers/setArrayRenderTargetLayers.ts +32 -0
- package/src/helpers/splitFrustum.ts +59 -0
- package/src/index.ts +14 -0
- package/src/qualityPresets.ts +117 -0
- package/src/r3f/CloudLayer.tsx +95 -0
- package/src/r3f/CloudLayers.tsx +54 -0
- package/src/r3f/Clouds.tsx +278 -0
- package/src/r3f/index.ts +2 -0
- package/src/shaders/catmullRomSampling.glsl +113 -0
- package/src/shaders/cloudShape.frag +78 -0
- package/src/shaders/cloudShapeDetail.frag +56 -0
- package/src/shaders/clouds.frag +996 -0
- package/src/shaders/clouds.glsl +190 -0
- package/src/shaders/clouds.vert +69 -0
- package/src/shaders/cloudsEffect.frag +11 -0
- package/src/shaders/cloudsResolve.frag +202 -0
- package/src/shaders/cloudsResolve.vert +10 -0
- package/src/shaders/localWeather.frag +83 -0
- package/src/shaders/parameters.glsl +64 -0
- package/src/shaders/perlin.glsl +211 -0
- package/src/shaders/shadow.frag +197 -0
- package/src/shaders/shadow.vert +16 -0
- package/src/shaders/shadowResolve.frag +76 -0
- package/src/shaders/shadowResolve.vert +10 -0
- package/src/shaders/structuredSampling.glsl +101 -0
- package/src/shaders/tileableNoise.glsl +88 -0
- package/src/shaders/turbulence.frag +51 -0
- package/src/shaders/types.glsl +18 -0
- package/src/shaders/varianceClipping.glsl +114 -0
- package/src/uniforms.ts +218 -0
- package/types/CascadedShadowMaps.d.ts +52 -0
- package/types/CloudLayer.d.ts +26 -0
- package/types/CloudLayers.d.ts +21 -0
- package/types/CloudShape.d.ts +5 -0
- package/types/CloudShapeDetail.d.ts +5 -0
- package/types/CloudsEffect.d.ts +170 -0
- package/types/CloudsMaterial.d.ts +86 -0
- package/types/CloudsPass.d.ts +44 -0
- package/types/CloudsResolveMaterial.d.ts +30 -0
- package/types/DensityProfile.d.ts +12 -0
- package/types/LocalWeather.d.ts +5 -0
- package/types/PassBase.d.ts +14 -0
- package/types/Procedural3DTexture.d.ts +20 -0
- package/types/ProceduralTexture.d.ts +24 -0
- package/types/ShaderArrayPass.d.ts +7 -0
- package/types/ShadowMaterial.d.ts +34 -0
- package/types/ShadowPass.d.ts +34 -0
- package/types/ShadowResolveMaterial.d.ts +20 -0
- package/types/Turbulence.d.ts +5 -0
- package/types/bayer.d.ts +4 -0
- package/types/constants.d.ts +6 -0
- package/types/helpers/FrustumCorners.d.ts +18 -0
- package/types/helpers/setArrayRenderTargetLayers.d.ts +3 -0
- package/types/helpers/splitFrustum.d.ts +9 -0
- package/types/index.d.ts +13 -0
- package/types/qualityPresets.d.ts +46 -0
- package/types/r3f/CloudLayer.d.ts +7 -0
- package/types/r3f/CloudLayers.d.ts +15 -0
- package/types/r3f/Clouds.d.ts +16 -0
- package/types/r3f/index.d.ts +2 -0
- package/types/uniforms.d.ts +66 -0
@@ -0,0 +1,211 @@
|
|
1
|
+
// Ported from GLM: https://github.com/g-truc/glm/blob/master/glm/gtc/noise.inl
|
2
|
+
|
3
|
+
/**
|
4
|
+
* OpenGL Mathematics (GLM)
|
5
|
+
*
|
6
|
+
* GLM is licensed under The Happy Bunny License or MIT License
|
7
|
+
*
|
8
|
+
* The Happy Bunny License (Modified MIT License)
|
9
|
+
*
|
10
|
+
* Copyright (c) 2005 - G-Truc Creation
|
11
|
+
*
|
12
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
13
|
+
* of this software and associated documentation files (the "Software"), to deal
|
14
|
+
* in the Software without restriction, including without limitation the rights
|
15
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
16
|
+
* copies of the Software, and to permit persons to whom the Software is
|
17
|
+
* furnished to do so, subject to the following conditions:
|
18
|
+
*
|
19
|
+
* The above copyright notice and this permission notice shall be included in
|
20
|
+
* all copies or substantial portions of the Software.
|
21
|
+
*
|
22
|
+
* Restrictions:
|
23
|
+
* By making use of the Software for military purposes, you choose to make a
|
24
|
+
* Bunny unhappy.
|
25
|
+
*
|
26
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
27
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
28
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
29
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
30
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
31
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
32
|
+
* THE SOFTWARE.
|
33
|
+
*
|
34
|
+
* The MIT License
|
35
|
+
*
|
36
|
+
* Copyright (c) 2005 - G-Truc Creation
|
37
|
+
*
|
38
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
39
|
+
* of this software and associated documentation files (the "Software"), to deal
|
40
|
+
* in the Software without restriction, including without limitation the rights
|
41
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
42
|
+
* copies of the Software, and to permit persons to whom the Software is
|
43
|
+
* furnished to do so, subject to the following conditions:
|
44
|
+
*
|
45
|
+
* The above copyright notice and this permission notice shall be included in
|
46
|
+
* all copies or substantial portions of the Software.
|
47
|
+
*
|
48
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
49
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
50
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
51
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
52
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
53
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
54
|
+
* THE SOFTWARE.
|
55
|
+
*/
|
56
|
+
|
57
|
+
vec4 mod289(const vec4 x) {
|
58
|
+
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
59
|
+
}
|
60
|
+
|
61
|
+
vec4 permute(const vec4 v) {
|
62
|
+
return mod289((v * 34.0 + 1.0) * v);
|
63
|
+
}
|
64
|
+
|
65
|
+
vec4 taylorInvSqrt(const vec4 r) {
|
66
|
+
return 1.79284291400159 - 0.85373472095314 * r;
|
67
|
+
}
|
68
|
+
|
69
|
+
vec4 fade(const vec4 v) {
|
70
|
+
return v * v * v * (v * (v * 6.0 - 15.0) + 10.0);
|
71
|
+
}
|
72
|
+
|
73
|
+
// Classic Perlin noise, periodic version
|
74
|
+
float perlin(const vec4 position, const vec4 rep) {
|
75
|
+
vec4 Pi0 = mod(floor(position), rep); // Integer part modulo rep
|
76
|
+
vec4 Pi1 = mod(Pi0 + 1.0, rep); // Integer part + 1 mod rep
|
77
|
+
vec4 Pf0 = fract(position); // Fractional part for interpolation
|
78
|
+
vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0
|
79
|
+
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
|
80
|
+
vec4 iy = vec4(Pi0.y, Pi0.y, Pi1.y, Pi1.y);
|
81
|
+
vec4 iz0 = vec4(Pi0.z);
|
82
|
+
vec4 iz1 = vec4(Pi1.z);
|
83
|
+
vec4 iw0 = vec4(Pi0.w);
|
84
|
+
vec4 iw1 = vec4(Pi1.w);
|
85
|
+
|
86
|
+
vec4 ixy = permute(permute(ix) + iy);
|
87
|
+
vec4 ixy0 = permute(ixy + iz0);
|
88
|
+
vec4 ixy1 = permute(ixy + iz1);
|
89
|
+
vec4 ixy00 = permute(ixy0 + iw0);
|
90
|
+
vec4 ixy01 = permute(ixy0 + iw1);
|
91
|
+
vec4 ixy10 = permute(ixy1 + iw0);
|
92
|
+
vec4 ixy11 = permute(ixy1 + iw1);
|
93
|
+
|
94
|
+
vec4 gx00 = ixy00 / 7.0;
|
95
|
+
vec4 gy00 = floor(gx00) / 7.0;
|
96
|
+
vec4 gz00 = floor(gy00) / 6.0;
|
97
|
+
gx00 = fract(gx00) - 0.5;
|
98
|
+
gy00 = fract(gy00) - 0.5;
|
99
|
+
gz00 = fract(gz00) - 0.5;
|
100
|
+
vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
|
101
|
+
vec4 sw00 = step(gw00, vec4(0));
|
102
|
+
gx00 -= sw00 * (step(0.0, gx00) - 0.5);
|
103
|
+
gy00 -= sw00 * (step(0.0, gy00) - 0.5);
|
104
|
+
|
105
|
+
vec4 gx01 = ixy01 / 7.0;
|
106
|
+
vec4 gy01 = floor(gx01) / 7.0;
|
107
|
+
vec4 gz01 = floor(gy01) / 6.0;
|
108
|
+
gx01 = fract(gx01) - 0.5;
|
109
|
+
gy01 = fract(gy01) - 0.5;
|
110
|
+
gz01 = fract(gz01) - 0.5;
|
111
|
+
vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
|
112
|
+
vec4 sw01 = step(gw01, vec4(0.0));
|
113
|
+
gx01 -= sw01 * (step(0.0, gx01) - 0.5);
|
114
|
+
gy01 -= sw01 * (step(0.0, gy01) - 0.5);
|
115
|
+
|
116
|
+
vec4 gx10 = ixy10 / 7.0;
|
117
|
+
vec4 gy10 = floor(gx10) / 7.0;
|
118
|
+
vec4 gz10 = floor(gy10) / 6.0;
|
119
|
+
gx10 = fract(gx10) - 0.5;
|
120
|
+
gy10 = fract(gy10) - 0.5;
|
121
|
+
gz10 = fract(gz10) - 0.5;
|
122
|
+
vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
|
123
|
+
vec4 sw10 = step(gw10, vec4(0.0));
|
124
|
+
gx10 -= sw10 * (step(0.0, gx10) - 0.5);
|
125
|
+
gy10 -= sw10 * (step(0.0, gy10) - 0.5);
|
126
|
+
|
127
|
+
vec4 gx11 = ixy11 / 7.0;
|
128
|
+
vec4 gy11 = floor(gx11) / 7.0;
|
129
|
+
vec4 gz11 = floor(gy11) / 6.0;
|
130
|
+
gx11 = fract(gx11) - 0.5;
|
131
|
+
gy11 = fract(gy11) - 0.5;
|
132
|
+
gz11 = fract(gz11) - 0.5;
|
133
|
+
vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
|
134
|
+
vec4 sw11 = step(gw11, vec4(0.0));
|
135
|
+
gx11 -= sw11 * (step(0.0, gx11) - 0.5);
|
136
|
+
gy11 -= sw11 * (step(0.0, gy11) - 0.5);
|
137
|
+
|
138
|
+
vec4 g0000 = vec4(gx00.x, gy00.x, gz00.x, gw00.x);
|
139
|
+
vec4 g1000 = vec4(gx00.y, gy00.y, gz00.y, gw00.y);
|
140
|
+
vec4 g0100 = vec4(gx00.z, gy00.z, gz00.z, gw00.z);
|
141
|
+
vec4 g1100 = vec4(gx00.w, gy00.w, gz00.w, gw00.w);
|
142
|
+
vec4 g0010 = vec4(gx10.x, gy10.x, gz10.x, gw10.x);
|
143
|
+
vec4 g1010 = vec4(gx10.y, gy10.y, gz10.y, gw10.y);
|
144
|
+
vec4 g0110 = vec4(gx10.z, gy10.z, gz10.z, gw10.z);
|
145
|
+
vec4 g1110 = vec4(gx10.w, gy10.w, gz10.w, gw10.w);
|
146
|
+
vec4 g0001 = vec4(gx01.x, gy01.x, gz01.x, gw01.x);
|
147
|
+
vec4 g1001 = vec4(gx01.y, gy01.y, gz01.y, gw01.y);
|
148
|
+
vec4 g0101 = vec4(gx01.z, gy01.z, gz01.z, gw01.z);
|
149
|
+
vec4 g1101 = vec4(gx01.w, gy01.w, gz01.w, gw01.w);
|
150
|
+
vec4 g0011 = vec4(gx11.x, gy11.x, gz11.x, gw11.x);
|
151
|
+
vec4 g1011 = vec4(gx11.y, gy11.y, gz11.y, gw11.y);
|
152
|
+
vec4 g0111 = vec4(gx11.z, gy11.z, gz11.z, gw11.z);
|
153
|
+
vec4 g1111 = vec4(gx11.w, gy11.w, gz11.w, gw11.w);
|
154
|
+
|
155
|
+
vec4 norm00 = taylorInvSqrt(
|
156
|
+
vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))
|
157
|
+
);
|
158
|
+
g0000 *= norm00.x;
|
159
|
+
g0100 *= norm00.y;
|
160
|
+
g1000 *= norm00.z;
|
161
|
+
g1100 *= norm00.w;
|
162
|
+
|
163
|
+
vec4 norm01 = taylorInvSqrt(
|
164
|
+
vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))
|
165
|
+
);
|
166
|
+
g0001 *= norm01.x;
|
167
|
+
g0101 *= norm01.y;
|
168
|
+
g1001 *= norm01.z;
|
169
|
+
g1101 *= norm01.w;
|
170
|
+
|
171
|
+
vec4 norm10 = taylorInvSqrt(
|
172
|
+
vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))
|
173
|
+
);
|
174
|
+
g0010 *= norm10.x;
|
175
|
+
g0110 *= norm10.y;
|
176
|
+
g1010 *= norm10.z;
|
177
|
+
g1110 *= norm10.w;
|
178
|
+
|
179
|
+
vec4 norm11 = taylorInvSqrt(
|
180
|
+
vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))
|
181
|
+
);
|
182
|
+
g0011 *= norm11.x;
|
183
|
+
g0111 *= norm11.y;
|
184
|
+
g1011 *= norm11.z;
|
185
|
+
g1111 *= norm11.w;
|
186
|
+
|
187
|
+
float n0000 = dot(g0000, Pf0);
|
188
|
+
float n1000 = dot(g1000, vec4(Pf1.x, Pf0.y, Pf0.z, Pf0.w));
|
189
|
+
float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.z, Pf0.w));
|
190
|
+
float n1100 = dot(g1100, vec4(Pf1.x, Pf1.y, Pf0.z, Pf0.w));
|
191
|
+
float n0010 = dot(g0010, vec4(Pf0.x, Pf0.y, Pf1.z, Pf0.w));
|
192
|
+
float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
|
193
|
+
float n0110 = dot(g0110, vec4(Pf0.x, Pf1.y, Pf1.z, Pf0.w));
|
194
|
+
float n1110 = dot(g1110, vec4(Pf1.x, Pf1.y, Pf1.z, Pf0.w));
|
195
|
+
float n0001 = dot(g0001, vec4(Pf0.x, Pf0.y, Pf0.z, Pf1.w));
|
196
|
+
float n1001 = dot(g1001, vec4(Pf1.x, Pf0.y, Pf0.z, Pf1.w));
|
197
|
+
float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
|
198
|
+
float n1101 = dot(g1101, vec4(Pf1.x, Pf1.y, Pf0.z, Pf1.w));
|
199
|
+
float n0011 = dot(g0011, vec4(Pf0.x, Pf0.y, Pf1.z, Pf1.w));
|
200
|
+
float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.z, Pf1.w));
|
201
|
+
float n0111 = dot(g0111, vec4(Pf0.x, Pf1.y, Pf1.z, Pf1.w));
|
202
|
+
float n1111 = dot(g1111, Pf1);
|
203
|
+
|
204
|
+
vec4 fade_xyzw = fade(Pf0);
|
205
|
+
vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w);
|
206
|
+
vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w);
|
207
|
+
vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z);
|
208
|
+
vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y);
|
209
|
+
float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
|
210
|
+
return 2.2 * n_xyzw;
|
211
|
+
}
|
@@ -0,0 +1,197 @@
|
|
1
|
+
precision highp float;
|
2
|
+
precision highp sampler3D;
|
3
|
+
|
4
|
+
#include <common>
|
5
|
+
|
6
|
+
#include "core/math"
|
7
|
+
#include "core/raySphereIntersection"
|
8
|
+
#include "types"
|
9
|
+
#include "parameters"
|
10
|
+
#include "structuredSampling"
|
11
|
+
#include "clouds"
|
12
|
+
|
13
|
+
uniform mat4 inverseShadowMatrices[CASCADE_COUNT];
|
14
|
+
uniform mat4 reprojectionMatrices[CASCADE_COUNT];
|
15
|
+
|
16
|
+
// Primary raymarch
|
17
|
+
uniform int maxIterationCount;
|
18
|
+
uniform float minStepSize;
|
19
|
+
uniform float maxStepSize;
|
20
|
+
uniform float opticalDepthTailScale;
|
21
|
+
|
22
|
+
in vec2 vUv;
|
23
|
+
in vec3 vEllipsoidCenter;
|
24
|
+
|
25
|
+
layout(location = 0) out vec4 outputColor[CASCADE_COUNT];
|
26
|
+
|
27
|
+
// Redundant notation for prettier.
|
28
|
+
#if CASCADE_COUNT == 1
|
29
|
+
layout(location = 1) out vec3 outputDepthVelocity[CASCADE_COUNT];
|
30
|
+
#elif CASCADE_COUNT == 2
|
31
|
+
layout(location = 2) out vec3 outputDepthVelocity[CASCADE_COUNT];
|
32
|
+
#elif CASCADE_COUNT == 3
|
33
|
+
layout(location = 3) out vec3 outputDepthVelocity[CASCADE_COUNT];
|
34
|
+
#elif CASCADE_COUNT == 4
|
35
|
+
layout(location = 4) out vec3 outputDepthVelocity[CASCADE_COUNT];
|
36
|
+
#endif // CASCADE_COUNT
|
37
|
+
|
38
|
+
vec4 marchClouds(
|
39
|
+
const vec3 rayOrigin,
|
40
|
+
const vec3 rayDirection,
|
41
|
+
const float maxRayDistance,
|
42
|
+
const float jitter,
|
43
|
+
const float mipLevel
|
44
|
+
) {
|
45
|
+
// Setup structured volume sampling (SVS).
|
46
|
+
// While SVS introduces spatial aliasing, it is indeed temporally stable,
|
47
|
+
// which is important for lower-resolution shadow maps where a flickering
|
48
|
+
// single pixel can be highly noticeable.
|
49
|
+
vec3 normal = getStructureNormal(rayDirection, jitter);
|
50
|
+
float rayDistance;
|
51
|
+
float stepSize;
|
52
|
+
intersectStructuredPlanes(
|
53
|
+
normal,
|
54
|
+
rayOrigin,
|
55
|
+
rayDirection,
|
56
|
+
clamp(maxRayDistance / float(maxIterationCount), minStepSize, maxStepSize),
|
57
|
+
rayDistance,
|
58
|
+
stepSize
|
59
|
+
);
|
60
|
+
|
61
|
+
#ifdef TEMPORAL_JITTER
|
62
|
+
rayDistance -= stepSize * jitter;
|
63
|
+
#endif // TEMPORAL_JITTER
|
64
|
+
|
65
|
+
float extinctionSum = 0.0;
|
66
|
+
float maxOpticalDepth = 0.0;
|
67
|
+
float maxOpticalDepthTail = 0.0;
|
68
|
+
float transmittanceIntegral = 1.0;
|
69
|
+
float weightedDistanceSum = 0.0;
|
70
|
+
float transmittanceSum = 0.0;
|
71
|
+
|
72
|
+
int sampleCount = 0;
|
73
|
+
for (int i = 0; i < maxIterationCount; ++i) {
|
74
|
+
if (rayDistance > maxRayDistance) {
|
75
|
+
break; // Termination
|
76
|
+
}
|
77
|
+
|
78
|
+
vec3 position = rayDistance * rayDirection + rayOrigin;
|
79
|
+
float height = length(position) - bottomRadius;
|
80
|
+
|
81
|
+
#if !defined(DEBUG_MARCH_INTERVALS)
|
82
|
+
if (insideLayerIntervals(height)) {
|
83
|
+
rayDistance += stepSize;
|
84
|
+
continue;
|
85
|
+
}
|
86
|
+
#endif // !defined(DEBUG_MARCH_INTERVALS)
|
87
|
+
|
88
|
+
// Sample rough weather.
|
89
|
+
vec2 uv = getGlobeUv(position);
|
90
|
+
WeatherSample weather = sampleWeather(uv, height, mipLevel);
|
91
|
+
|
92
|
+
if (any(greaterThan(weather.density, vec4(minDensity)))) {
|
93
|
+
// Sample detailed participating media.
|
94
|
+
// Note this assumes an homogeneous medium.
|
95
|
+
MediaSample media = sampleMedia(weather, position, uv, mipLevel, jitter);
|
96
|
+
if (media.extinction > minExtinction) {
|
97
|
+
extinctionSum += media.extinction;
|
98
|
+
maxOpticalDepth += media.extinction * stepSize;
|
99
|
+
transmittanceIntegral *= exp(-media.extinction * stepSize);
|
100
|
+
weightedDistanceSum += rayDistance * transmittanceIntegral;
|
101
|
+
transmittanceSum += transmittanceIntegral;
|
102
|
+
++sampleCount;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
if (transmittanceIntegral <= minTransmittance) {
|
107
|
+
// A large amount of optical depth accumulates in the tail, beyond the
|
108
|
+
// point of minimum transmittance. The expected optical depth seems to
|
109
|
+
// decrease exponentially with the number of samples taken before reaching
|
110
|
+
// the minimum transmittance.
|
111
|
+
// See the discussion here: https://x.com/shotamatsuda/status/1886259549931520437
|
112
|
+
maxOpticalDepthTail = min(
|
113
|
+
opticalDepthTailScale * stepSize * exp(float(1 - sampleCount)),
|
114
|
+
stepSize * 0.5 // Excessive optical depth only introduces aliasing.
|
115
|
+
);
|
116
|
+
break; // Early termination
|
117
|
+
}
|
118
|
+
rayDistance += stepSize;
|
119
|
+
}
|
120
|
+
|
121
|
+
if (sampleCount == 0) {
|
122
|
+
return vec4(maxRayDistance, 0.0, 0.0, 0.0);
|
123
|
+
}
|
124
|
+
float frontDepth = min(weightedDistanceSum / transmittanceSum, maxRayDistance);
|
125
|
+
float meanExtinction = extinctionSum / float(sampleCount);
|
126
|
+
return vec4(frontDepth, meanExtinction, maxOpticalDepth, maxOpticalDepthTail);
|
127
|
+
}
|
128
|
+
|
129
|
+
void getRayNearFar(
|
130
|
+
const vec3 sunPosition,
|
131
|
+
const vec3 rayDirection,
|
132
|
+
out float rayNear,
|
133
|
+
out float rayFar
|
134
|
+
) {
|
135
|
+
vec4 firstIntersections = raySphereFirstIntersection(
|
136
|
+
sunPosition,
|
137
|
+
rayDirection,
|
138
|
+
vec3(0.0),
|
139
|
+
bottomRadius + vec4(shadowTopHeight, shadowBottomHeight, 0.0, 0.0)
|
140
|
+
);
|
141
|
+
rayNear = max(0.0, firstIntersections.x);
|
142
|
+
rayFar = firstIntersections.y;
|
143
|
+
if (rayFar < 0.0) {
|
144
|
+
rayFar = 1e6;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
void cascade(
|
149
|
+
const int cascadeIndex,
|
150
|
+
const float mipLevel,
|
151
|
+
out vec4 outputColor,
|
152
|
+
out vec3 outputDepthVelocity
|
153
|
+
) {
|
154
|
+
vec2 clip = vUv * 2.0 - 1.0;
|
155
|
+
vec4 point = inverseShadowMatrices[cascadeIndex] * vec4(clip.xy, -1.0, 1.0);
|
156
|
+
point /= point.w;
|
157
|
+
vec3 sunPosition = mat3(inverseEllipsoidMatrix) * point.xyz - vEllipsoidCenter;
|
158
|
+
|
159
|
+
// The sun direction is in ECEF. Since the view matrix is constructed with the
|
160
|
+
// ellipsoid matrix already applied, there's no need to apply the inverse
|
161
|
+
// matrix here.
|
162
|
+
vec3 rayDirection = normalize(-sunDirection);
|
163
|
+
float rayNear;
|
164
|
+
float rayFar;
|
165
|
+
getRayNearFar(sunPosition, rayDirection, rayNear, rayFar);
|
166
|
+
|
167
|
+
vec3 rayOrigin = rayNear * rayDirection + sunPosition;
|
168
|
+
float stbn = getSTBN();
|
169
|
+
vec4 color = marchClouds(rayOrigin, rayDirection, rayFar - rayNear, stbn, mipLevel);
|
170
|
+
outputColor = color;
|
171
|
+
|
172
|
+
// Velocity for temporal resolution.
|
173
|
+
#ifdef TEMPORAL_PASS
|
174
|
+
vec3 frontPosition = color.x * rayDirection + rayOrigin;
|
175
|
+
vec3 frontPositionWorld = mat3(ellipsoidMatrix) * (frontPosition + vEllipsoidCenter);
|
176
|
+
vec4 prevClip = reprojectionMatrices[cascadeIndex] * vec4(frontPositionWorld, 1.0);
|
177
|
+
prevClip /= prevClip.w;
|
178
|
+
vec2 prevUv = prevClip.xy * 0.5 + 0.5;
|
179
|
+
vec2 velocity = (vUv - prevUv) * resolution;
|
180
|
+
outputDepthVelocity = vec3(color.x, velocity);
|
181
|
+
#else // TEMPORAL_PASS
|
182
|
+
outputDepthVelocity = vec3(0.0);
|
183
|
+
#endif // TEMPORAL_PASS
|
184
|
+
}
|
185
|
+
|
186
|
+
// TODO: Calculate from the main camera frustum perhaps?
|
187
|
+
const float mipLevels[4] = float[4](0.0, 0.5, 1.0, 2.0);
|
188
|
+
|
189
|
+
void main() {
|
190
|
+
#pragma unroll_loop_start
|
191
|
+
for (int i = 0; i < 4; ++i) {
|
192
|
+
#if UNROLLED_LOOP_INDEX < CASCADE_COUNT
|
193
|
+
cascade(UNROLLED_LOOP_INDEX, mipLevels[i], outputColor[i], outputDepthVelocity[i]);
|
194
|
+
#endif // UNROLLED_LOOP_INDEX < CASCADE_COUNT
|
195
|
+
}
|
196
|
+
#pragma unroll_loop_end
|
197
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
precision highp float;
|
2
|
+
|
3
|
+
uniform vec3 ellipsoidCenter;
|
4
|
+
uniform vec3 altitudeCorrection;
|
5
|
+
|
6
|
+
layout(location = 0) in vec3 position;
|
7
|
+
|
8
|
+
out vec2 vUv;
|
9
|
+
out vec3 vEllipsoidCenter;
|
10
|
+
|
11
|
+
void main() {
|
12
|
+
vUv = position.xy * 0.5 + 0.5;
|
13
|
+
vEllipsoidCenter = ellipsoidCenter + altitudeCorrection;
|
14
|
+
|
15
|
+
gl_Position = vec4(position.xy, 1.0, 1.0);
|
16
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
precision highp float;
|
2
|
+
precision highp sampler2DArray;
|
3
|
+
|
4
|
+
#define VARIANCE_9_SAMPLES (1)
|
5
|
+
#define VARIANCE_SAMPLER_ARRAY (1)
|
6
|
+
|
7
|
+
#include "varianceClipping"
|
8
|
+
|
9
|
+
uniform sampler2DArray inputBuffer;
|
10
|
+
uniform sampler2DArray historyBuffer;
|
11
|
+
|
12
|
+
uniform vec2 texelSize;
|
13
|
+
uniform float varianceGamma;
|
14
|
+
uniform float temporalAlpha;
|
15
|
+
|
16
|
+
in vec2 vUv;
|
17
|
+
|
18
|
+
layout(location = 0) out vec4 outputColor[CASCADE_COUNT];
|
19
|
+
|
20
|
+
const ivec2 neighborOffsets[9] = ivec2[9](
|
21
|
+
ivec2(-1, -1),
|
22
|
+
ivec2(-1, 0),
|
23
|
+
ivec2(-1, 1),
|
24
|
+
ivec2(0, -1),
|
25
|
+
ivec2(0, 0),
|
26
|
+
ivec2(0, 1),
|
27
|
+
ivec2(1, -1),
|
28
|
+
ivec2(1, 0),
|
29
|
+
ivec2(1, 1)
|
30
|
+
);
|
31
|
+
|
32
|
+
vec4 getClosestFragment(const ivec3 coord) {
|
33
|
+
vec4 result = vec4(1e7, 0.0, 0.0, 0.0);
|
34
|
+
vec4 neighbor;
|
35
|
+
#pragma unroll_loop_start
|
36
|
+
for (int i = 0; i < 9; ++i) {
|
37
|
+
neighbor = texelFetchOffset(
|
38
|
+
inputBuffer,
|
39
|
+
coord + ivec3(0, 0, CASCADE_COUNT),
|
40
|
+
0,
|
41
|
+
neighborOffsets[i]
|
42
|
+
);
|
43
|
+
if (neighbor.r < result.r) {
|
44
|
+
result = neighbor;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
#pragma unroll_loop_end
|
48
|
+
return result;
|
49
|
+
}
|
50
|
+
|
51
|
+
void cascade(const int cascadeIndex, out vec4 outputColor) {
|
52
|
+
ivec3 coord = ivec3(gl_FragCoord.xy, cascadeIndex);
|
53
|
+
vec4 current = texelFetch(inputBuffer, coord, 0);
|
54
|
+
|
55
|
+
vec4 depthVelocity = getClosestFragment(coord);
|
56
|
+
vec2 velocity = depthVelocity.gb * texelSize;
|
57
|
+
vec2 prevUv = vUv - velocity;
|
58
|
+
if (prevUv.x < 0.0 || prevUv.x > 1.0 || prevUv.y < 0.0 || prevUv.y > 1.0) {
|
59
|
+
outputColor = current;
|
60
|
+
return; // Rejection
|
61
|
+
}
|
62
|
+
|
63
|
+
vec4 history = texture(historyBuffer, vec3(prevUv, float(cascadeIndex)));
|
64
|
+
vec4 clippedHistory = varianceClipping(inputBuffer, coord, current, history, varianceGamma);
|
65
|
+
outputColor = mix(clippedHistory, current, temporalAlpha);
|
66
|
+
}
|
67
|
+
|
68
|
+
void main() {
|
69
|
+
#pragma unroll_loop_start
|
70
|
+
for (int i = 0; i < 4; ++i) {
|
71
|
+
#if UNROLLED_LOOP_INDEX < CASCADE_COUNT
|
72
|
+
cascade(UNROLLED_LOOP_INDEX, outputColor[i]);
|
73
|
+
#endif // UNROLLED_LOOP_INDEX < CASCADE_COUNT
|
74
|
+
}
|
75
|
+
#pragma unroll_loop_end
|
76
|
+
}
|
@@ -0,0 +1,101 @@
|
|
1
|
+
// Implements Structured Volume Sampling in fragment shader:
|
2
|
+
// https://github.com/huwb/volsample
|
3
|
+
// Implementation reference:
|
4
|
+
// https://www.shadertoy.com/view/ttVfDc
|
5
|
+
|
6
|
+
void getIcosahedralVertices(const vec3 direction, out vec3 v1, out vec3 v2, out vec3 v3) {
|
7
|
+
// Normalization scalers to fit dodecahedron to unit sphere.
|
8
|
+
const float a = 0.85065080835204; // phi / sqrt(2 + phi)
|
9
|
+
const float b = 0.5257311121191336; // 1 / sqrt(2 + phi)
|
10
|
+
|
11
|
+
// Derive the vertices of icosahedron where triangle intersects the direction.
|
12
|
+
// See: https://www.ppsloan.org/publications/AmbientDice.pdf
|
13
|
+
const float kT = 0.6180339887498948; // 1 / phi
|
14
|
+
const float kT2 = 0.38196601125010515; // 1 / phi^2
|
15
|
+
vec3 absD = abs(direction);
|
16
|
+
float selector1 = dot(absD, vec3(1.0, kT2, -kT));
|
17
|
+
float selector2 = dot(absD, vec3(-kT, 1.0, kT2));
|
18
|
+
float selector3 = dot(absD, vec3(kT2, -kT, 1.0));
|
19
|
+
v1 = selector1 > 0.0 ? vec3(a, b, 0.0) : vec3(-b, 0.0, a);
|
20
|
+
v2 = selector2 > 0.0 ? vec3(0.0, a, b) : vec3(a, -b, 0.0);
|
21
|
+
v3 = selector3 > 0.0 ? vec3(b, 0.0, a) : vec3(0.0, a, -b);
|
22
|
+
vec3 octantSign = sign(direction);
|
23
|
+
v1 *= octantSign;
|
24
|
+
v2 *= octantSign;
|
25
|
+
v3 *= octantSign;
|
26
|
+
}
|
27
|
+
|
28
|
+
void swapIfBigger(inout vec4 a, inout vec4 b) {
|
29
|
+
if (a.w > b.w) {
|
30
|
+
vec4 t = a;
|
31
|
+
a = b;
|
32
|
+
b = t;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
void sortVertices(inout vec3 a, inout vec3 b, inout vec3 c) {
|
37
|
+
const vec3 base = vec3(0.5, 0.5, 1.0);
|
38
|
+
vec4 aw = vec4(a, dot(a, base));
|
39
|
+
vec4 bw = vec4(b, dot(b, base));
|
40
|
+
vec4 cw = vec4(c, dot(c, base));
|
41
|
+
swapIfBigger(aw, bw);
|
42
|
+
swapIfBigger(bw, cw);
|
43
|
+
swapIfBigger(aw, bw);
|
44
|
+
a = aw.xyz;
|
45
|
+
b = bw.xyz;
|
46
|
+
c = cw.xyz;
|
47
|
+
}
|
48
|
+
|
49
|
+
vec3 getPentagonalWeights(const vec3 direction, const vec3 v1, const vec3 v2, const vec3 v3) {
|
50
|
+
float d1 = dot(v1, direction);
|
51
|
+
float d2 = dot(v2, direction);
|
52
|
+
float d3 = dot(v3, direction);
|
53
|
+
vec3 w = exp(vec3(d1, d2, d3) * 40.0);
|
54
|
+
return w / (w.x + w.y + w.z);
|
55
|
+
}
|
56
|
+
|
57
|
+
vec3 getStructureNormal(
|
58
|
+
const vec3 direction,
|
59
|
+
const float jitter,
|
60
|
+
out vec3 a,
|
61
|
+
out vec3 b,
|
62
|
+
out vec3 c,
|
63
|
+
out vec3 weights
|
64
|
+
) {
|
65
|
+
getIcosahedralVertices(direction, a, b, c);
|
66
|
+
sortVertices(a, b, c);
|
67
|
+
weights = getPentagonalWeights(direction, a, b, c);
|
68
|
+
return jitter < weights.x
|
69
|
+
? a
|
70
|
+
: jitter < weights.x + weights.y
|
71
|
+
? b
|
72
|
+
: c;
|
73
|
+
}
|
74
|
+
|
75
|
+
vec3 getStructureNormal(const vec3 direction, const float jitter) {
|
76
|
+
vec3 a, b, c, weights;
|
77
|
+
return getStructureNormal(direction, jitter, a, b, c, weights);
|
78
|
+
}
|
79
|
+
|
80
|
+
// Reference: https://github.com/huwb/volsample/blob/master/src/unity/Assets/Shaders/RayMarchCore.cginc
|
81
|
+
void intersectStructuredPlanes(
|
82
|
+
const vec3 normal,
|
83
|
+
const vec3 rayOrigin,
|
84
|
+
const vec3 rayDirection,
|
85
|
+
const float samplePeriod,
|
86
|
+
out float stepOffset,
|
87
|
+
out float stepSize
|
88
|
+
) {
|
89
|
+
float NoD = dot(rayDirection, normal);
|
90
|
+
stepSize = samplePeriod / abs(NoD);
|
91
|
+
|
92
|
+
// Skips leftover bit to get from rayOrigin to first strata plane.
|
93
|
+
stepOffset = -mod(dot(rayOrigin, normal), samplePeriod) / NoD;
|
94
|
+
|
95
|
+
// mod() gives different results depending on if the arg is negative or
|
96
|
+
// positive. This line makes it consistent, and ensures the first sample is in
|
97
|
+
// front of the viewer.
|
98
|
+
if (stepOffset < 0.0) {
|
99
|
+
stepOffset += stepSize;
|
100
|
+
}
|
101
|
+
}
|
@@ -0,0 +1,88 @@
|
|
1
|
+
// Based on the following work with slight modifications.
|
2
|
+
// https://github.com/sebh/TileableVolumeNoise
|
3
|
+
|
4
|
+
/**
|
5
|
+
* The MIT License (MIT)
|
6
|
+
*
|
7
|
+
* Copyright(c) 2017 Sébastien Hillaire
|
8
|
+
*
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
* of this software and associated documentation files (the "Software"), to deal
|
11
|
+
* in the Software without restriction, including without limitation the rights
|
12
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
* copies of the Software, and to permit persons to whom the Software is
|
14
|
+
* furnished to do so, subject to the following conditions:
|
15
|
+
*
|
16
|
+
* The above copyright notice and this permission notice shall be included in
|
17
|
+
* all copies or substantial portions of the Software.
|
18
|
+
*
|
19
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
25
|
+
* SOFTWARE.
|
26
|
+
*/
|
27
|
+
|
28
|
+
float hash(const float n) {
|
29
|
+
return fract(sin(n + 1.951) * 43758.5453);
|
30
|
+
}
|
31
|
+
|
32
|
+
float noise(const vec3 x) {
|
33
|
+
vec3 p = floor(x);
|
34
|
+
vec3 f = fract(x);
|
35
|
+
|
36
|
+
f = f * f * (3.0 - 2.0 * f);
|
37
|
+
float n = p.x + p.y * 57.0 + 113.0 * p.z;
|
38
|
+
return mix(
|
39
|
+
mix(mix(hash(n + 0.0), hash(n + 1.0), f.x), mix(hash(n + 57.0), hash(n + 58.0), f.x), f.y),
|
40
|
+
mix(
|
41
|
+
mix(hash(n + 113.0), hash(n + 114.0), f.x),
|
42
|
+
mix(hash(n + 170.0), hash(n + 171.0), f.x),
|
43
|
+
f.y
|
44
|
+
),
|
45
|
+
f.z
|
46
|
+
);
|
47
|
+
}
|
48
|
+
|
49
|
+
float getWorleyNoise(const vec3 p, const float cellCount) {
|
50
|
+
vec3 cell = p * cellCount;
|
51
|
+
float d = 1.0e10;
|
52
|
+
for (int x = -1; x <= 1; ++x) {
|
53
|
+
for (int y = -1; y <= 1; ++y) {
|
54
|
+
for (int z = -1; z <= 1; ++z) {
|
55
|
+
vec3 tp = floor(cell) + vec3(x, y, z);
|
56
|
+
tp = cell - tp - noise(mod(tp, cellCount / 1.0));
|
57
|
+
d = min(d, dot(tp, tp));
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
return clamp(d, 0.0, 1.0);
|
62
|
+
}
|
63
|
+
|
64
|
+
float getPerlinNoise(const vec3 point, const vec3 frequency, const int octaveCount) {
|
65
|
+
// Noise frequency factor between octave, forced to 2.
|
66
|
+
const float octaveFrequencyFactor = 2.0;
|
67
|
+
|
68
|
+
// Compute the sum for each octave.
|
69
|
+
float sum = 0.0;
|
70
|
+
float roughness = 0.5;
|
71
|
+
float weightSum = 0.0;
|
72
|
+
float weight = 1.0;
|
73
|
+
vec3 nextFrequency = frequency;
|
74
|
+
for (int i = 0; i < octaveCount; ++i) {
|
75
|
+
vec4 p = vec4(point.x, point.y, point.z, 0.0) * vec4(nextFrequency, 1.0);
|
76
|
+
float value = perlin(p, vec4(nextFrequency, 1.0));
|
77
|
+
sum += value * weight;
|
78
|
+
weightSum += weight;
|
79
|
+
weight *= roughness;
|
80
|
+
nextFrequency *= octaveFrequencyFactor;
|
81
|
+
}
|
82
|
+
|
83
|
+
return sum / weightSum; // Intentionally skip clamping.
|
84
|
+
}
|
85
|
+
|
86
|
+
float getPerlinNoise(const vec3 point, const float frequency, const int octaveCount) {
|
87
|
+
return getPerlinNoise(point, vec3(frequency), octaveCount);
|
88
|
+
}
|