├── LICENSE
├── base.css
├── index.html
├── main.js
└── resources
├── negx.jpg
├── negy.jpg
├── negz.jpg
├── posx.jpg
├── posy.jpg
├── posz.jpg
└── readme.txt
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 simondevyoutube
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/base.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 100%;
3 | height: 100%;
4 | position: absolute;
5 | background: #000000;
6 | margin: 0;
7 | padding: 0;
8 | overscroll-behavior: none;
9 | }
10 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Three.JS Tutorial: Fogggggg
5 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.124/build/three.module.js';
2 |
3 | import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/three@0.124/examples/jsm/controls/OrbitControls.js';
4 |
5 |
6 | const _NOISE_GLSL = `
7 | //
8 | // Description : Array and textureless GLSL 2D/3D/4D simplex
9 | // noise functions.
10 | // Author : Ian McEwan, Ashima Arts.
11 | // Maintainer : stegu
12 | // Lastmod : 20201014 (stegu)
13 | // License : Copyright (C) 2011 Ashima Arts. All rights reserved.
14 | // Distributed under the MIT License. See LICENSE file.
15 | // https://github.com/ashima/webgl-noise
16 | // https://github.com/stegu/webgl-noise
17 | //
18 |
19 | vec3 mod289(vec3 x) {
20 | return x - floor(x * (1.0 / 289.0)) * 289.0;
21 | }
22 |
23 | vec4 mod289(vec4 x) {
24 | return x - floor(x * (1.0 / 289.0)) * 289.0;
25 | }
26 |
27 | vec4 permute(vec4 x) {
28 | return mod289(((x*34.0)+1.0)*x);
29 | }
30 |
31 | vec4 taylorInvSqrt(vec4 r)
32 | {
33 | return 1.79284291400159 - 0.85373472095314 * r;
34 | }
35 |
36 | float snoise(vec3 v)
37 | {
38 | const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
39 | const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
40 |
41 | // First corner
42 | vec3 i = floor(v + dot(v, C.yyy) );
43 | vec3 x0 = v - i + dot(i, C.xxx) ;
44 |
45 | // Other corners
46 | vec3 g = step(x0.yzx, x0.xyz);
47 | vec3 l = 1.0 - g;
48 | vec3 i1 = min( g.xyz, l.zxy );
49 | vec3 i2 = max( g.xyz, l.zxy );
50 |
51 | // x0 = x0 - 0.0 + 0.0 * C.xxx;
52 | // x1 = x0 - i1 + 1.0 * C.xxx;
53 | // x2 = x0 - i2 + 2.0 * C.xxx;
54 | // x3 = x0 - 1.0 + 3.0 * C.xxx;
55 | vec3 x1 = x0 - i1 + C.xxx;
56 | vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
57 | vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
58 |
59 | // Permutations
60 | i = mod289(i);
61 | vec4 p = permute( permute( permute(
62 | i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
63 | + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
64 | + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
65 |
66 | // Gradients: 7x7 points over a square, mapped onto an octahedron.
67 | // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
68 | float n_ = 0.142857142857; // 1.0/7.0
69 | vec3 ns = n_ * D.wyz - D.xzx;
70 |
71 | vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
72 |
73 | vec4 x_ = floor(j * ns.z);
74 | vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
75 |
76 | vec4 x = x_ *ns.x + ns.yyyy;
77 | vec4 y = y_ *ns.x + ns.yyyy;
78 | vec4 h = 1.0 - abs(x) - abs(y);
79 |
80 | vec4 b0 = vec4( x.xy, y.xy );
81 | vec4 b1 = vec4( x.zw, y.zw );
82 |
83 | //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
84 | //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
85 | vec4 s0 = floor(b0)*2.0 + 1.0;
86 | vec4 s1 = floor(b1)*2.0 + 1.0;
87 | vec4 sh = -step(h, vec4(0.0));
88 |
89 | vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
90 | vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
91 |
92 | vec3 p0 = vec3(a0.xy,h.x);
93 | vec3 p1 = vec3(a0.zw,h.y);
94 | vec3 p2 = vec3(a1.xy,h.z);
95 | vec3 p3 = vec3(a1.zw,h.w);
96 |
97 | //Normalise gradients
98 | vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
99 | p0 *= norm.x;
100 | p1 *= norm.y;
101 | p2 *= norm.z;
102 | p3 *= norm.w;
103 |
104 | // Mix final noise value
105 | vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
106 | m = m * m;
107 | return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
108 | dot(p2,x2), dot(p3,x3) ) );
109 | }
110 |
111 | float FBM(vec3 p) {
112 | float value = 0.0;
113 | float amplitude = 0.5;
114 | float frequency = 0.0;
115 | for (int i = 0; i < 6; ++i) {
116 | value += amplitude * snoise(p);
117 | p *= 2.0;
118 | amplitude *= 0.5;
119 | }
120 | return value;
121 | }
122 | `;
123 |
124 |
125 | class FogDemo {
126 | constructor() {
127 | this.Initialize_();
128 | }
129 |
130 | Initialize_() {
131 |
132 | THREE.ShaderChunk.fog_fragment = `
133 | #ifdef USE_FOG
134 | vec3 fogOrigin = cameraPosition;
135 | vec3 fogDirection = normalize(vWorldPosition - fogOrigin);
136 | float fogDepth = distance(vWorldPosition, fogOrigin);
137 |
138 | // f(p) = fbm( p + fbm( p ) )
139 | vec3 noiseSampleCoord = vWorldPosition * 0.00025 + vec3(
140 | 0.0, 0.0, fogTime * 0.025);
141 | float noiseSample = FBM(noiseSampleCoord + FBM(noiseSampleCoord)) * 0.5 + 0.5;
142 | fogDepth *= mix(noiseSample, 1.0, saturate((fogDepth - 5000.0) / 5000.0));
143 | fogDepth *= fogDepth;
144 |
145 | float heightFactor = 0.05;
146 | float fogFactor = heightFactor * exp(-fogOrigin.y * fogDensity) * (
147 | 1.0 - exp(-fogDepth * fogDirection.y * fogDensity)) / fogDirection.y;
148 | fogFactor = saturate(fogFactor);
149 |
150 | gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );
151 | #endif`;
152 |
153 | THREE.ShaderChunk.fog_pars_fragment = _NOISE_GLSL + `
154 | #ifdef USE_FOG
155 | uniform float fogTime;
156 | uniform vec3 fogColor;
157 | varying vec3 vWorldPosition;
158 | #ifdef FOG_EXP2
159 | uniform float fogDensity;
160 | #else
161 | uniform float fogNear;
162 | uniform float fogFar;
163 | #endif
164 | #endif`;
165 |
166 | THREE.ShaderChunk.fog_vertex = `
167 | #ifdef USE_FOG
168 | vWorldPosition = worldPosition.xyz;
169 | #endif`;
170 |
171 | THREE.ShaderChunk.fog_pars_vertex = `
172 | #ifdef USE_FOG
173 | varying vec3 vWorldPosition;
174 | #endif`;
175 |
176 | this.threejs_ = new THREE.WebGLRenderer({
177 | antialias: true,
178 | });
179 | this.threejs_.shadowMap.enabled = true;
180 | this.threejs_.shadowMap.type = THREE.PCFSoftShadowMap;
181 | this.threejs_.setPixelRatio(window.devicePixelRatio);
182 | this.threejs_.setSize(window.innerWidth, window.innerHeight);
183 |
184 | document.body.appendChild(this.threejs_.domElement);
185 |
186 | window.addEventListener('resize', () => {
187 | this.OnWindowResize_();
188 | }, false);
189 |
190 | const fov = 60;
191 | const aspect = 1920 / 1080;
192 | const near = 1.0;
193 | const far = 20000.0;
194 | this.camera_ = new THREE.PerspectiveCamera(fov, aspect, near, far);
195 | this.camera_.position.set(75, 20, 0);
196 |
197 | this.scene_ = new THREE.Scene();
198 |
199 | let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
200 | light.position.set(20, 100, 10);
201 | light.target.position.set(0, 0, 0);
202 | light.castShadow = true;
203 | light.shadow.bias = -0.001;
204 | light.shadow.mapSize.width = 2048;
205 | light.shadow.mapSize.height = 2048;
206 | light.shadow.camera.near = 0.1;
207 | light.shadow.camera.far = 500.0;
208 | light.shadow.camera.near = 0.5;
209 | light.shadow.camera.far = 500.0;
210 | light.shadow.camera.left = 100;
211 | light.shadow.camera.right = -100;
212 | light.shadow.camera.top = 100;
213 | light.shadow.camera.bottom = -100;
214 | this.scene_.add(light);
215 |
216 | light = new THREE.AmbientLight(0x101010);
217 | this.scene_.add(light);
218 |
219 | const controls = new OrbitControls(
220 | this.camera_, this.threejs_.domElement);
221 | controls.target.set(0, 20, 0);
222 | controls.update();
223 |
224 | this.shaders_ = [];
225 | const ModifyShader_ = (s) => {
226 | this.shaders_.push(s);
227 | s.uniforms.fogTime = {value: 0.0};
228 | }
229 |
230 | const sky = new THREE.Mesh(
231 | new THREE.SphereGeometry(10000, 32, 32),
232 | new THREE.MeshBasicMaterial({
233 | color: 0x8080FF,
234 | side: THREE.BackSide,
235 | })
236 | );
237 | sky.material.onBeforeCompile = ModifyShader_;
238 | this.scene_.add(sky);
239 |
240 | const ground = new THREE.Mesh(
241 | new THREE.PlaneGeometry(20000, 20000, 300, 300),
242 | new THREE.MeshStandardMaterial({
243 | color: 0x808080,
244 | })
245 | );
246 | ground.rotation.x = -Math.PI / 2.0;
247 | ground.material.onBeforeCompile = ModifyShader_;
248 | this.scene_.add(ground);
249 |
250 | const trunkMat = new THREE.MeshStandardMaterial({color: 0x808080});
251 | const leavesMat = new THREE.MeshStandardMaterial({color: 0x80FF80});
252 | const trunkGeo = new THREE.BoxGeometry(1, 1, 1);
253 | const leavesGeo = new THREE.ConeGeometry(1, 1, 32);
254 |
255 | trunkMat.onBeforeCompile = ModifyShader_;
256 | leavesMat.onBeforeCompile = ModifyShader_;
257 |
258 | for (let x = 0; x < 50; ++x) {
259 | for (let y = 0; y < 50; ++y) {
260 | const trunk = new THREE.Mesh(trunkGeo, trunkMat);
261 | const leaves = new THREE.Mesh(leavesGeo, leavesMat);
262 | trunk.scale.set(20, (Math.random() + 1.0) * 100.0, 20);
263 | trunk.position.set(
264 | 15000.0 * (Math.random() * 2.0 - 1.0),
265 | trunk.scale.y / 2.0,
266 | 15000.0 * (Math.random() * 2.0 - 1.0));
267 |
268 | leaves.scale.copy(trunk.scale);
269 | leaves.scale.set(100, trunk.scale.y * 5.0, 100);
270 | leaves.position.set(
271 | trunk.position.x,
272 | leaves.scale.y / 2 + (Math.random() + 1) * 25,
273 | trunk.position.z);
274 |
275 | this.scene_.add(trunk);
276 | this.scene_.add(leaves);
277 | }
278 | }
279 |
280 | const monolith = new THREE.Mesh(
281 | new THREE.BoxGeometry(500, 2000, 100),
282 | new THREE.MeshStandardMaterial({color: 0x000000, metalness: 0.9}));
283 | monolith.position.set(0, 1000, 5000);
284 | monolith.material.onBeforeCompile = ModifyShader_;
285 | this.scene_.add(monolith);
286 |
287 | // this.scene_.fog = new THREE.Fog(0xDFE9F3, 0.0, 500.0);
288 | this.scene_.fog = new THREE.FogExp2(0xDFE9F3, 0.0000005);
289 |
290 | this.totalTime_ = 0.0;
291 | this.previousRAF_ = null;
292 | this.RAF_();
293 | }
294 |
295 | OnWindowResize_() {
296 | this.camera_.aspect = window.innerWidth / window.innerHeight;
297 | this.camera_.updateProjectionMatrix();
298 | this.threejs_.setSize(window.innerWidth, window.innerHeight);
299 | }
300 |
301 | RAF_() {
302 | requestAnimationFrame((t) => {
303 | if (this.previousRAF_ === null) {
304 | this.previousRAF_ = t;
305 | }
306 |
307 | this.Step_((t - this.previousRAF_) * 0.001);
308 | this.previousRAF_ = t;
309 |
310 | this.threejs_.render(this.scene_, this.camera_);
311 | this.RAF_();
312 | });
313 | }
314 |
315 | Step_(timeElapsed) {
316 | this.totalTime_ += timeElapsed;
317 | for (let s of this.shaders_) {
318 | s.uniforms.fogTime.value = this.totalTime_;
319 | }
320 | }
321 | }
322 |
323 |
324 | let _APP = null;
325 |
326 | window.addEventListener('DOMContentLoaded', () => {
327 | _APP = new FogDemo();
328 | });
329 |
--------------------------------------------------------------------------------
/resources/negx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_Fog/8f927d475a5b29e7aa937c468634c0b76b6e1eb1/resources/negx.jpg
--------------------------------------------------------------------------------
/resources/negy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_Fog/8f927d475a5b29e7aa937c468634c0b76b6e1eb1/resources/negy.jpg
--------------------------------------------------------------------------------
/resources/negz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_Fog/8f927d475a5b29e7aa937c468634c0b76b6e1eb1/resources/negz.jpg
--------------------------------------------------------------------------------
/resources/posx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_Fog/8f927d475a5b29e7aa937c468634c0b76b6e1eb1/resources/posx.jpg
--------------------------------------------------------------------------------
/resources/posy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_Fog/8f927d475a5b29e7aa937c468634c0b76b6e1eb1/resources/posy.jpg
--------------------------------------------------------------------------------
/resources/posz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_Fog/8f927d475a5b29e7aa937c468634c0b76b6e1eb1/resources/posz.jpg
--------------------------------------------------------------------------------
/resources/readme.txt:
--------------------------------------------------------------------------------
1 | Author
2 | ======
3 |
4 | This is the work of Emil Persson, aka Humus.
5 | http://www.humus.name
6 |
7 |
8 |
9 | License
10 | =======
11 |
12 | This work is licensed under a Creative Commons Attribution 3.0 Unported License.
13 | http://creativecommons.org/licenses/by/3.0/
14 |
--------------------------------------------------------------------------------