├── 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 | --------------------------------------------------------------------------------