123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- import * as THREE from 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js';
- import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/OrbitControls.js';
- const _NOISE_GLSL = `
- //
- // Description : Array and textureless GLSL 2D/3D/4D simplex
- // noise functions.
- // Author : Ian McEwan, Ashima Arts.
- // Maintainer : stegu
- // Lastmod : 20201014 (stegu)
- // License : Copyright (C) 2011 Ashima Arts. All rights reserved.
- // Distributed under the MIT License. See LICENSE file.
- // https://github.com/ashima/webgl-noise
- // https://github.com/stegu/webgl-noise
- //
- vec3 mod289(vec3 x) {
- return x - floor(x * (1.0 / 289.0)) * 289.0;
- }
- vec4 mod289(vec4 x) {
- return x - floor(x * (1.0 / 289.0)) * 289.0;
- }
- vec4 permute(vec4 x) {
- return mod289(((x*34.0)+1.0)*x);
- }
- vec4 taylorInvSqrt(vec4 r)
- {
- return 1.79284291400159 - 0.85373472095314 * r;
- }
- float snoise(vec3 v)
- {
- const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
- const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
- // First corner
- vec3 i = floor(v + dot(v, C.yyy) );
- vec3 x0 = v - i + dot(i, C.xxx) ;
- // Other corners
- vec3 g = step(x0.yzx, x0.xyz);
- vec3 l = 1.0 - g;
- vec3 i1 = min( g.xyz, l.zxy );
- vec3 i2 = max( g.xyz, l.zxy );
- // x0 = x0 - 0.0 + 0.0 * C.xxx;
- // x1 = x0 - i1 + 1.0 * C.xxx;
- // x2 = x0 - i2 + 2.0 * C.xxx;
- // x3 = x0 - 1.0 + 3.0 * C.xxx;
- vec3 x1 = x0 - i1 + C.xxx;
- vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
- vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
- // Permutations
- i = mod289(i);
- vec4 p = permute( permute( permute(
- i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
- + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
- + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
- // Gradients: 7x7 points over a square, mapped onto an octahedron.
- // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
- float n_ = 0.142857142857; // 1.0/7.0
- vec3 ns = n_ * D.wyz - D.xzx;
- vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
- vec4 x_ = floor(j * ns.z);
- vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
- vec4 x = x_ *ns.x + ns.yyyy;
- vec4 y = y_ *ns.x + ns.yyyy;
- vec4 h = 1.0 - abs(x) - abs(y);
- vec4 b0 = vec4( x.xy, y.xy );
- vec4 b1 = vec4( x.zw, y.zw );
- //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
- //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
- vec4 s0 = floor(b0)*2.0 + 1.0;
- vec4 s1 = floor(b1)*2.0 + 1.0;
- vec4 sh = -step(h, vec4(0.0));
- vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
- vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
- vec3 p0 = vec3(a0.xy,h.x);
- vec3 p1 = vec3(a0.zw,h.y);
- vec3 p2 = vec3(a1.xy,h.z);
- vec3 p3 = vec3(a1.zw,h.w);
- //Normalise gradients
- vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
- p0 *= norm.x;
- p1 *= norm.y;
- p2 *= norm.z;
- p3 *= norm.w;
- // Mix final noise value
- vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
- m = m * m;
- return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
- dot(p2,x2), dot(p3,x3) ) );
- }
- float FBM(vec3 p) {
- float value = 0.0;
- float amplitude = 0.5;
- float frequency = 0.0;
- for (int i = 0; i < 6; ++i) {
- value += amplitude * snoise(p);
- p *= 2.0;
- amplitude *= 0.5;
- }
- return value;
- }
- `;
- class FogDemo {
- constructor() {
- this.Initialize_();
- }
- Initialize_() {
- THREE.ShaderChunk.fog_fragment = `
- #ifdef USE_FOG
- vec3 fogOrigin = cameraPosition;
- vec3 fogDirection = normalize(vWorldPosition - fogOrigin);
- float fogDepth = distance(vWorldPosition, fogOrigin);
- // f(p) = fbm( p + fbm( p ) )
- vec3 noiseSampleCoord = vWorldPosition * 0.00025 + vec3(
- 0.0, 0.0, fogTime * 0.025);
- float noiseSample = FBM(noiseSampleCoord + FBM(noiseSampleCoord)) * 0.5 + 0.5;
- fogDepth *= mix(noiseSample, 1.0, saturate((fogDepth - 5000.0) / 5000.0));
- fogDepth *= fogDepth;
- float heightFactor = 0.05;
- float fogFactor = heightFactor * exp(-fogOrigin.y * fogDensity) * (
- 1.0 - exp(-fogDepth * fogDirection.y * fogDensity)) / fogDirection.y;
- fogFactor = saturate(fogFactor);
- gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );
- #endif`;
-
- THREE.ShaderChunk.fog_pars_fragment = _NOISE_GLSL + `
- #ifdef USE_FOG
- uniform float fogTime;
- uniform vec3 fogColor;
- varying vec3 vWorldPosition;
- #ifdef FOG_EXP2
- uniform float fogDensity;
- #else
- uniform float fogNear;
- uniform float fogFar;
- #endif
- #endif`;
-
- THREE.ShaderChunk.fog_vertex = `
- #ifdef USE_FOG
- vWorldPosition = worldPosition.xyz;
- #endif`;
-
- THREE.ShaderChunk.fog_pars_vertex = `
- #ifdef USE_FOG
- varying vec3 vWorldPosition;
- #endif`;
- this.threejs_ = new THREE.WebGLRenderer({
- antialias: true,
- });
- this.threejs_.shadowMap.enabled = true;
- this.threejs_.shadowMap.type = THREE.PCFSoftShadowMap;
- this.threejs_.setPixelRatio(window.devicePixelRatio);
- this.threejs_.setSize(window.innerWidth, window.innerHeight);
- document.body.appendChild(this.threejs_.domElement);
- window.addEventListener('resize', () => {
- this.OnWindowResize_();
- }, false);
- const fov = 60;
- const aspect = 1920 / 1080;
- const near = 1.0;
- const far = 20000.0;
- this.camera_ = new THREE.PerspectiveCamera(fov, aspect, near, far);
- this.camera_.position.set(75, 20, 0);
- this.scene_ = new THREE.Scene();
- let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
- light.position.set(20, 100, 10);
- light.target.position.set(0, 0, 0);
- light.castShadow = true;
- light.shadow.bias = -0.001;
- light.shadow.mapSize.width = 2048;
- light.shadow.mapSize.height = 2048;
- light.shadow.camera.near = 0.1;
- light.shadow.camera.far = 500.0;
- light.shadow.camera.near = 0.5;
- light.shadow.camera.far = 500.0;
- light.shadow.camera.left = 100;
- light.shadow.camera.right = -100;
- light.shadow.camera.top = 100;
- light.shadow.camera.bottom = -100;
- this.scene_.add(light);
- light = new THREE.AmbientLight(0x101010);
- this.scene_.add(light);
- const controls = new OrbitControls(
- this.camera_, this.threejs_.domElement);
- controls.target.set(0, 20, 0);
- controls.update();
- this.shaders_ = [];
- const ModifyShader_ = (s) => {
- this.shaders_.push(s);
- s.uniforms.fogTime = {value: 0.0};
- }
- const sky = new THREE.Mesh(
- new THREE.SphereGeometry(10000, 32, 32),
- new THREE.MeshBasicMaterial({
- color: 0x8080FF,
- side: THREE.BackSide,
- })
- );
- sky.material.onBeforeCompile = ModifyShader_;
- this.scene_.add(sky);
- const ground = new THREE.Mesh(
- new THREE.PlaneGeometry(20000, 20000, 300, 300),
- new THREE.MeshStandardMaterial({
- color: 0x808080,
- })
- );
- ground.rotation.x = -Math.PI / 2.0;
- ground.material.onBeforeCompile = ModifyShader_;
- this.scene_.add(ground);
- const trunkMat = new THREE.MeshStandardMaterial({color: 0x808080});
- const leavesMat = new THREE.MeshStandardMaterial({color: 0x80FF80});
- const trunkGeo = new THREE.BoxGeometry(1, 1, 1);
- const leavesGeo = new THREE.ConeGeometry(1, 1, 32);
- trunkMat.onBeforeCompile = ModifyShader_;
- leavesMat.onBeforeCompile = ModifyShader_;
- for (let x = 0; x < 50; ++x) {
- for (let y = 0; y < 50; ++y) {
- const trunk = new THREE.Mesh(trunkGeo, trunkMat);
- const leaves = new THREE.Mesh(leavesGeo, leavesMat);
- trunk.scale.set(20, (Math.random() + 1.0) * 100.0, 20);
- trunk.position.set(
- 15000.0 * (Math.random() * 2.0 - 1.0),
- trunk.scale.y / 2.0,
- 15000.0 * (Math.random() * 2.0 - 1.0));
- leaves.scale.copy(trunk.scale);
- leaves.scale.set(100, trunk.scale.y * 5.0, 100);
- leaves.position.set(
- trunk.position.x,
- leaves.scale.y / 2 + (Math.random() + 1) * 25,
- trunk.position.z);
- this.scene_.add(trunk);
- this.scene_.add(leaves);
- }
- }
- const monolith = new THREE.Mesh(
- new THREE.BoxGeometry(500, 2000, 100),
- new THREE.MeshStandardMaterial({color: 0x000000, metalness: 0.9}));
- monolith.position.set(0, 1000, 5000);
- monolith.material.onBeforeCompile = ModifyShader_;
- this.scene_.add(monolith);
- // this.scene_.fog = new THREE.Fog(0xDFE9F3, 0.0, 500.0);
- this.scene_.fog = new THREE.FogExp2(0xDFE9F3, 0.0000005);
- this.totalTime_ = 0.0;
- this.previousRAF_ = null;
- this.RAF_();
- }
- OnWindowResize_() {
- this.camera_.aspect = window.innerWidth / window.innerHeight;
- this.camera_.updateProjectionMatrix();
- this.threejs_.setSize(window.innerWidth, window.innerHeight);
- }
- RAF_() {
- requestAnimationFrame((t) => {
- if (this.previousRAF_ === null) {
- this.previousRAF_ = t;
- }
- this.Step_((t - this.previousRAF_) * 0.001);
- this.previousRAF_ = t;
-
- this.threejs_.render(this.scene_, this.camera_);
- this.RAF_();
- });
- }
- Step_(timeElapsed) {
- this.totalTime_ += timeElapsed;
- for (let s of this.shaders_) {
- s.uniforms.fogTime.value = this.totalTime_;
- }
- }
- }
- let _APP = null;
- window.addEventListener('DOMContentLoaded', () => {
- _APP = new FogDemo();
- });
|