/** * Fog shader effect. */ class FogShader extends AbstractWeatherShader { /** @inheritdoc */ static defaultUniforms = { intensity: 1, rotation: 0, slope: 0.25 }; /* ---------------------------------------- */ /** * Configure the number of octaves into the shaders. * @param {number} mode * @returns {string} */ static OCTAVES(mode) { return `${mode + 2}`; } /* -------------------------------------------- */ /** * Configure the fog complexity according to mode (performance). * @param {number} mode * @returns {string} */ static FOG(mode) { if ( mode === 0 ) { return `vec2 mv = vec2(fbm(uv * 4.5 + time * 0.115)) * (1.0 + r * 0.25); mist += fbm(uv * 4.5 + mv - time * 0.0275) * (1.0 + r * 0.25);`; } return `for ( int i=0; i<2; i++ ) { vec2 mv = vec2(fbm(uv * 4.5 + time * 0.115 + vec2(float(i) * 250.0))) * (0.50 + r * 0.25); mist += fbm(uv * 4.5 + mv - time * 0.0275) * (0.50 + r * 0.25); }`; } /* -------------------------------------------- */ /** @override */ static createProgram() { const mode = canvas?.performance.mode ?? 2; return PIXI.Program.from(this.vertexShader, this.fragmentShader(mode)); } /* -------------------------------------------- */ /** @inheritdoc */ static fragmentShader(mode) { return ` ${this.FRAGMENT_HEADER} uniform float intensity; uniform float slope; uniform float rotation; ${this.CONSTANTS} ${this.PERCEIVED_BRIGHTNESS} ${this.PRNG} ${this.ROTATION} // ********************************************************* // float fnoise(in vec2 coords) { vec2 i = floor(coords); vec2 f = fract(coords); float a = random(i); float b = random(i + vec2(1.0, 0.0)); float c = random(i + vec2(0.0, 1.0)); float d = random(i + vec2(1.0, 1.0)); vec2 cb = f * f * (3.0 - 2.0 * f); return mix(a, b, cb.x) + (c - a) * cb.y * (1.0 - cb.x) + (d - b) * cb.x * cb.y; } // ********************************************************* // float fbm(in vec2 uv) { float r = 0.0; float scale = 1.0; uv += time * 0.03; uv *= 2.0; for (int i = 0; i < ${this.OCTAVES(mode)}; i++) { r += fnoise(uv + time * 0.03) * scale; uv *= 3.0; scale *= 0.3; } return r; } // ********************************************************* // vec3 mist(in vec2 uv, in float r) { float mist = 0.0; ${this.FOG(mode)} return vec3(0.9, 0.85, 1.0) * mist; } // ********************************************************* // void main() { ${this.COMPUTE_MASK} vec2 ruv; if ( rotation != 0.0 ) { ruv = vUvs - 0.5; ruv *= rot(rotation); ruv += 0.5; } else { ruv = vUvs; } vec3 col = mist(ruv * 2.0 - 1.0, 0.0) * 1.33; float pb = perceivedBrightness(col); pb = smoothstep(slope * 0.5, slope + 0.001, pb); gl_FragColor = vec4( mix(vec3(0.05, 0.05, 0.08), col * clamp(slope, 1.0, 2.0), pb), 1.0) * vec4(tint, 1.0) * intensity * mask * alpha; } `; } }