diff --git a/debug/fog.html b/debug/fog.html index 35926b424ba..7b0e8cd2b42 100644 --- a/debug/fog.html +++ b/debug/fog.html @@ -36,9 +36,6 @@ this.start = 2; this.end = 12.0; this.color = [255, 255, 255]; - this.hazeColor = [109, 123, 180]; - this.hazeOpacity = 0.5; - this.density = 1.0; this.horizonBlend = 0.1; this.showTileBoundaries = false; }; @@ -103,8 +100,6 @@ map.setFog(value ? { "range": [guiParams.start, guiParams.end], "color": 'rgba(' + guiParams.color[0] + ', ' + guiParams.color[1] + ', ' + guiParams.color[2] + ', 1.0)', - "haze-color": 'rgba(' + guiParams.hazeColor[0] + ', ' + guiParams.hazeColor[1] + ', ' + guiParams.hazeColor[2] + ', ' + guiParams.hazeOpacity + ')', - "density": guiParams.density, "horizon-blend": guiParams.horizonBlend } : null); }); @@ -123,13 +118,6 @@ }); }); - var density = fog.add(guiParams, 'density', 0, 1); - density.onChange((value) => { - map.setFog({ - "density": value, - }); - }); - var horizonBlend = fog.add(guiParams, 'horizonBlend', 0.0, 1.0); horizonBlend.onChange((value) => { map.setFog({ @@ -143,20 +131,6 @@ "color": 'rgba(' + value[0] + ', ' + value[1] + ', ' + value[2] + ', 1.0)', }); }); - - var hazeColor = fog.addColor(guiParams, 'hazeColor'); - hazeColor.onChange((value) => { - map.setFog({ - "haze-color": 'rgba(' + value[0] + ', ' + value[1] + ', ' + value[2] + ', ' + guiParams.hazeOpacity + ')', - }); - }); - - var hazeOpacity = fog.add(guiParams, 'hazeOpacity', 0, 1); - hazeOpacity.onChange((value) => { - map.setFog({ - "haze-color": 'rgba(' + guiParams.hazeColor[0] + ', ' + guiParams.hazeColor[1] + ', ' + guiParams.hazeColor[2] + ', ' + guiParams.hazeOpacity + ')', - }); - }); }; var popup = new mapboxgl.Popup().setHTML('Pitch Alignment: auto
Rotation Alignment: auto'); @@ -216,8 +190,6 @@ map.setFog(guiParams.enableFog ? { "range": [guiParams.start, guiParams.end], "color": 'rgba(' + guiParams.color[0] + ', ' + guiParams.color[1] + ', ' + guiParams.color[2] + ', 1.0)', - "haze-color": 'rgba(' + guiParams.hazeColor[0] + ', ' + guiParams.hazeColor[1] + ', ' + guiParams.hazeColor[2] + ', ' + guiParams.hazeOpacity + ')', - "density": guiParams.density, "horizon-blend": guiParams.horizonBlend } : null); diff --git a/src/render/fog.js b/src/render/fog.js index 7e857998df7..a5767f82b35 100644 --- a/src/render/fog.js +++ b/src/render/fog.js @@ -9,12 +9,8 @@ export type FogUniformsType = {| 'u_fog_matrix': UniformMatrix4f, 'u_fog_range': Uniform2f, 'u_fog_color': Uniform3f, - 'u_fog_exponent': Uniform1f, 'u_fog_horizon_blend': Uniform1f, 'u_fog_temporal_offset': Uniform1f, - 'u_haze_color_linear': Uniform3f, - - // Precision may differ, so we must pass uniforms separately for use in a vertex shader 'u_fog_opacity': Uniform1f, |}; @@ -23,10 +19,7 @@ export const fogUniforms = (context: Context, locations: UniformLocations): FogU 'u_fog_matrix': new UniformMatrix4f(context, locations.u_fog_matrix), 'u_fog_range': new Uniform2f(context, locations.u_fog_range), 'u_fog_color': new Uniform3f(context, locations.u_fog_color), - 'u_fog_exponent': new Uniform1f(context, locations.u_fog_exponent), 'u_fog_horizon_blend': new Uniform1f(context, locations.u_fog_horizon_blend), 'u_fog_temporal_offset': new Uniform1f(context, locations.u_fog_temporal_offset), - 'u_haze_color_linear': new Uniform3f(context, locations.u_haze_color_linear), - 'u_fog_opacity': new Uniform1f(context, locations.u_fog_opacity), }); diff --git a/src/render/painter.js b/src/render/painter.js index 5c5874876ac..e16ffe32a88 100644 --- a/src/render/painter.js +++ b/src/render/painter.js @@ -188,11 +188,10 @@ class Painter { const fog = this.style.fog; const fogStart = fog.properties.get('range')[0]; const fogEnd = fog.properties.get('range')[1]; - const fogDensity = fog.properties.get('density'); + // We start culling where the fog opacity function hits 98%, leaving - // a non-noticeable opacity change threshold. We use an arbitrary function - // which bounds the true answer. See: https://www.desmos.com/calculator/lw03ldsuhy - const fogBoundFraction = 1 - 0.22 * Math.exp(4 * (fogDensity - 1)); + // a non-noticeable opacity change threshold. + const fogBoundFraction = 0.78; const fogCullDist = fogStart + (fogEnd - fogStart) * fogBoundFraction; this.transform.fogCullDistSq = fogCullDist * fogCullDist; @@ -755,16 +754,12 @@ class Painter { const rtt = this.terrain && this.terrain.renderingToTexture; const fog = this.style && this.style.fog; const fogOpacity = fog && fog.getFogPitchFactor(this.transform.pitch); - const haze = fog && fog.properties && fog.properties.get('haze-color').a > 0; const defines = []; if (terrain) defines.push('TERRAIN'); // When terrain is active, fog is rendered as part of draping, not as part of tile // rendering. Removing the fog flag during tile rendering avoids additional defines. - if (fog && fogOpacity !== 0.0 && !rtt) { - defines.push('FOG'); - if (haze) defines.push('FOG_HAZE'); - } + if (fog && fogOpacity !== 0.0 && !rtt) defines.push('FOG'); if (rtt) defines.push('RENDER_TO_TEXTURE'); if (this._showOverdrawInspector) defines.push('OVERDRAW_INSPECTOR'); return defines; @@ -857,24 +852,10 @@ class Painter { uniforms['u_fog_matrix'] = tileID ? this.transform.calculateFogTileMatrix(tileID) : this.identityMat; uniforms['u_fog_range'] = fog.properties.get('range'); uniforms['u_fog_color'] = fogColorUnpremultiplied; - uniforms['u_fog_exponent'] = Math.max(1e-3, 12 * Math.pow(1 - fog.properties.get('density'), 2)); uniforms['u_fog_horizon_blend'] = fog.properties.get('horizon-blend'); uniforms['u_fog_temporal_offset'] = temporalOffset; uniforms['u_fog_opacity'] = fogOpacity; - if (fog.properties.get('haze-color').a > 0) { - const hazeColor = fog.properties.get('haze-color'); - const hazeBaseAmpl = 5; - // Since there's no significant difference in visual effect, we use approximate - // sRGB -> linear RGB conversion with a power of 2 instead of 2.2 in order to - // avoid pow() functions in the shader. - uniforms['u_haze_color_linear'] = [ - hazeBaseAmpl * Math.pow(hazeColor.r, 2), - hazeBaseAmpl * Math.pow(hazeColor.g, 2), - hazeBaseAmpl * Math.pow(hazeColor.b, 2), - ]; - } - program.setFogUniformValues(context, uniforms); } } diff --git a/src/shaders/_prelude.glsl b/src/shaders/_prelude.glsl index 0d0e63a7b6b..0814a70f28c 100644 --- a/src/shaders/_prelude.glsl +++ b/src/shaders/_prelude.glsl @@ -9,7 +9,7 @@ uniform mediump vec2 u_fog_range; uniform mediump float u_fog_horizon_blend; float fog_range(float depth) { - // Map [near, far] to [0, 1] + // Map [near, far] to [0, 1] without clamping return (depth - u_fog_range[0]) / (u_fog_range[1] - u_fog_range[0]); } @@ -25,8 +25,7 @@ float fog_horizon_blending(vec3 camera_dir) { return u_fog_opacity * exp(-3.0 * t * t); } -// Computes the fog opacity when fog strength = 1. Otherwise it's multiplied -// by a smoothstep to a power to decrease the amount of fog relative to haze. +// Compute a ramp for fog opacity // - t: depth, rescaled to 0 at fogStart and 1 at fogEnd // See: https://www.desmos.com/calculator/3taufutxid // This function much match src/style/fog.js and _prelude_fog.vertex.glsl @@ -34,7 +33,7 @@ float fog_opacity(float t) { const float decay = 6.0; float falloff = 1.0 - min(1.0, exp(-decay * t)); - // Cube without pow() + // Cube without pow() to smooth the onset falloff *= falloff * falloff; // Scale and clip to 1 at the far limit diff --git a/src/shaders/_prelude_fog.fragment.glsl b/src/shaders/_prelude_fog.fragment.glsl index acdc8524e58..e128699b545 100644 --- a/src/shaders/_prelude_fog.fragment.glsl +++ b/src/shaders/_prelude_fog.fragment.glsl @@ -2,8 +2,6 @@ uniform vec3 u_fog_color; uniform float u_fog_temporal_offset; -uniform mediump vec3 u_haze_color_linear; -uniform mediump float u_fog_exponent; // This function is only used in rare places like heatmap where opacity is used // directly, outside the normal fog_apply method. @@ -11,40 +9,16 @@ float fog_opacity(vec3 pos) { return fog_opacity(fog_range(length(pos))); } -// This function applies haze to an input color using an approximation of the following algorithm: -// 1. convert color from sRGB to linear RGB -// 2. add haze (presuming haze is in linear RGB) -// 3. tone-map the output -// 4. convert the result back to sRGB -// The equation below is based on a curve fit of the above algorithm, with the additional approximation -// during linear-srgb conversion that gamma=2, in order to avoid transcendental function evaluations -// which don't affect the visual quality. -vec3 haze_apply(vec3 color, vec3 haze) { - vec3 color2 = color * color; - return sqrt((color2 + haze) / (1.0 + color2 * color * haze)); -} - vec3 fog_apply(vec3 color, vec3 pos) { float depth = length(pos); float t = fog_range(depth); - - float haze_opac = fog_opacity(t); - float fog_opac = haze_opac * pow(smoothstep(0.0, 1.0, t), u_fog_exponent); - fog_opac *= fog_horizon_blending(pos / depth); - -#ifdef FOG_HAZE - color = haze_apply(color, haze_opac * u_haze_color_linear); -#endif + float fog_opac = fog_opacity(t) * fog_horizon_blending(pos / depth); return mix(color, u_fog_color, fog_opac); } -// Apply fog and haze which were computed in the vertex shader -vec3 fog_apply_from_vert(vec3 color, float fog_opac, vec3 haze) { -#ifdef FOG_HAZE - color = haze_apply(color, haze); -#endif - +// Apply fog computed in the vertex shader +vec3 fog_apply_from_vert(vec3 color, float fog_opac) { return mix(color, u_fog_color, fog_opac); } diff --git a/src/shaders/_prelude_fog.vertex.glsl b/src/shaders/_prelude_fog.vertex.glsl index 6175cf1d97e..00ff3111df2 100644 --- a/src/shaders/_prelude_fog.vertex.glsl +++ b/src/shaders/_prelude_fog.vertex.glsl @@ -1,8 +1,6 @@ #ifdef FOG uniform mat4 u_fog_matrix; -uniform mediump float u_fog_exponent; -uniform mediump vec3 u_haze_color_linear; vec3 fog_position(vec3 pos) { // The following function requires that u_fog_matrix be affine and result in @@ -15,16 +13,10 @@ vec3 fog_position(vec2 pos) { return fog_position(vec3(pos, 0)); } -void fog(vec3 pos, out float fog_opac, out vec3 haze) { +float fog(vec3 pos) { float depth = length(pos); - float t = fog_range(depth); - float haze_opac = fog_opacity(t); - fog_opac = haze_opac * pow(smoothstep(0.0, 1.0, t), u_fog_exponent); - fog_opac *= fog_horizon_blending(pos / depth); - -#ifdef FOG_HAZE - haze.rgb = haze_opac * u_haze_color_linear; -#endif + float opacity = fog_opacity(fog_range(depth)); + return opacity * fog_horizon_blending(pos / depth); } #endif diff --git a/src/shaders/terrain_raster.fragment.glsl b/src/shaders/terrain_raster.fragment.glsl index 652849fd363..9c6462f46a2 100644 --- a/src/shaders/terrain_raster.fragment.glsl +++ b/src/shaders/terrain_raster.fragment.glsl @@ -3,20 +3,12 @@ varying vec2 v_pos0; #ifdef FOG varying float v_fog_opacity; -#ifdef FOG_HAZE -varying vec3 v_haze_color; -#endif #endif void main() { vec4 color = texture2D(u_image0, v_pos0); #ifdef FOG -#ifdef FOG_HAZE - color.rgb = fog_dither(fog_apply_from_vert(color.rgb, v_fog_opacity, v_haze_color)); -#else - vec3 unused; - color.rgb = fog_dither(fog_apply_from_vert(color.rgb, v_fog_opacity, unused)); -#endif + color.rgb = fog_dither(fog_apply_from_vert(color.rgb, v_fog_opacity)); #endif gl_FragColor = color; #ifdef TERRAIN_WIREFRAME diff --git a/src/shaders/terrain_raster.vertex.glsl b/src/shaders/terrain_raster.vertex.glsl index b8c69503d34..aeb274d711b 100644 --- a/src/shaders/terrain_raster.vertex.glsl +++ b/src/shaders/terrain_raster.vertex.glsl @@ -8,9 +8,6 @@ varying vec2 v_pos0; #ifdef FOG varying float v_fog_opacity; -#ifdef FOG_HAZE -varying vec3 v_haze_color; -#endif #endif const float skirtOffset = 24575.0; @@ -27,11 +24,6 @@ void main() { gl_Position = u_matrix * vec4(decodedPos, elevation, 1.0); #ifdef FOG -#ifdef FOG_HAZE - fog(fog_position(vec3(decodedPos, elevation)), v_fog_opacity, v_haze_color); -#else - vec3 unused; - fog(fog_position(vec3(decodedPos, elevation)), v_fog_opacity, unused); -#endif + v_fog_opacity = fog(fog_position(vec3(decodedPos, elevation))); #endif } diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index df02684f0fb..978da0cb8b8 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -3725,43 +3725,6 @@ } } }, - "density": { - "type": "number", - "property-type": "data-constant", - "default": 1.0, - "minimum": 0.0, - "expression": { - "interpolated": true, - "parameters": [ - "zoom" - ] - }, - "transition": true, - "doc": "Controls the strength of fog within the fog range. Reducing the density pushes the fog farther toward the horizon, leaving more visible space for haze, if enabled. When haze opacity is zero, density will usually be 1.0.", - "sdk-support": { - "basic functionality": { - "js": "2.3.0" - } - } - }, - "haze-color": { - "type": "color", - "property-type": "data-constant", - "default": "rgba(114,135,213,0)", - "expression": { - "interpolated": true, - "parameters": [ - "zoom" - ] - }, - "transition": true, - "doc": "The color of the haze component of fog. Alpha adjusts the amount of haze. Note that haze is disabled by default (zero alpha); increase this value to enable the effect.", - "sdk-support": { - "basic functionality": { - "js": "2.3.0" - } - } - }, "horizon-blend": { "type": "number", "property-type": "data-constant", diff --git a/src/style-spec/types.js b/src/style-spec/types.js index e9ae6258dc2..8f0e07f2b75 100644 --- a/src/style-spec/types.js +++ b/src/style-spec/types.js @@ -90,8 +90,6 @@ export type TerrainSpecification = {| export type FogSpecification = {| "range"?: PropertyValueSpecification<[number, number]>, "color"?: PropertyValueSpecification, - "density"?: PropertyValueSpecification, - "haze-color"?: PropertyValueSpecification, "horizon-blend"?: PropertyValueSpecification |} diff --git a/src/style/fog.js b/src/style/fog.js index 30a3434c64c..237724e289b 100644 --- a/src/style/fog.js +++ b/src/style/fog.js @@ -17,16 +17,12 @@ import type {FogState} from './fog_helpers.js'; type Props = {| "range": DataConstantProperty<[number, number]>, "color": DataConstantProperty, - "density": DataConstantProperty, - "haze-color": DataConstantProperty, "horizon-blend": DataConstantProperty, |}; const fogProperties: Properties = new Properties({ "range": new DataConstantProperty(styleSpec.fog.range), "color": new DataConstantProperty(styleSpec.fog.color), - "density": new DataConstantProperty(styleSpec.fog["density"]), - "haze-color": new DataConstantProperty(styleSpec.fog["haze-color"]), "horizon-blend": new DataConstantProperty(styleSpec.fog["horizon-blend"]), }); @@ -47,7 +43,6 @@ class Fog extends Evented { get state(): FogState { return { range: this.properties.get('range'), - density: this.properties.get('density'), horizonBlend: this.properties.get('horizon-blend') }; } diff --git a/src/style/fog_helpers.js b/src/style/fog_helpers.js index 236de338d1a..9cd3b0727a5 100644 --- a/src/style/fog_helpers.js +++ b/src/style/fog_helpers.js @@ -12,7 +12,6 @@ export const FOG_SYMBOL_CLIPPING_THRESHOLD = 0.9; export type FogState = { range: [number, number], - density: number, horizonBlend: number }; @@ -26,7 +25,6 @@ export function getFogHorizonBlending(state: FogState, cameraDirection: Array, pitch: number): number { const fogOpacity = smoothstep(FOG_PITCH_START, FOG_PITCH_END, pitch); const [start, end] = state.range; - const fogDensity = state.density; // The fog is not physically accurate, so we seek an expression which satisfies a // couple basic constraints: @@ -49,12 +47,6 @@ export function getFogOpacity(state: FogState, pos: Array, pitch: number // Scale and clip to 1 at the far limit falloff = Math.min(1.0, 1.00747 * falloff); - // From src/render/painter.js via fog uniforms: - const fogExponent = 12 * Math.pow(1 - fogDensity, 2); - - // Account for fog density - falloff *= Math.pow(smoothstep(0, 1, t), fogExponent); - const cameraDirection = vec3.scale(vec3.create(), pos, 1.0 / depth); falloff *= getFogHorizonBlending(state, cameraDirection); diff --git a/src/ui/map.js b/src/ui/map.js index 8e49e16d632..82ff451113f 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -2184,8 +2184,6 @@ class Map extends Camera { * map.setFog({ * "range": [1.0, 12.0], * "color": 'white', - * "density": 1.0, - * "haze-color": 'rgba(109, 123, 180, 0.5)', * "horizon-blend": 0.1 * }); */ diff --git a/test/integration/render-tests/fog/terrain/density/expected.png b/test/integration/render-tests/fog/terrain/density/expected.png deleted file mode 100644 index 868ce9d7b34..00000000000 Binary files a/test/integration/render-tests/fog/terrain/density/expected.png and /dev/null differ diff --git a/test/integration/render-tests/fog/terrain/density/style.json b/test/integration/render-tests/fog/terrain/density/style.json deleted file mode 100644 index 762e12c970c..00000000000 --- a/test/integration/render-tests/fog/terrain/density/style.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "height": 256, - "width": 256 - } - }, - "center": [-113.32296, 35.94662], - "zoom": 12.1, - "pitch": 80, - "bearing": 64.5, - "terrain": { - "source": "rgbterrain" - }, - "fog": { - "range": [1, 2], - "color": "white", - "density": 0.2 - }, - "sources": { - "rgbterrain": { - "type": "raster-dem", - "tiles": [ - "local://tiles/{z}-{x}-{y}.terrain.png" - ], - "maxzoom": 12, - "tileSize": 256 - }, - "satellite": { - "type": "raster", - "tiles": [ - "local://tiles/{z}-{x}-{y}.satellite.png" - ], - "maxzoom": 17, - "tileSize": 256 - } - }, - "layers": [ - { - "id": "sky", - "type": "sky", - "paint": { - "sky-type": "gradient", - "sky-gradient-center": [0, 0], - "sky-gradient-radius": 90, - "sky-gradient": [ - "interpolate", - ["linear"], - ["sky-radial-progress"], - 0.0, - "#87ceeb", - 1.0, - "#87ceeb" - ] - } - }, - { - "id": "raster", - "type": "raster", - "source": "satellite", - "paint": { - "raster-fade-duration": 0 - } - } - ] -} diff --git a/test/integration/render-tests/fog/terrain/haze/expected.png b/test/integration/render-tests/fog/terrain/haze/expected.png deleted file mode 100644 index ee6c2f2cc26..00000000000 Binary files a/test/integration/render-tests/fog/terrain/haze/expected.png and /dev/null differ diff --git a/test/integration/render-tests/fog/terrain/haze/style.json b/test/integration/render-tests/fog/terrain/haze/style.json deleted file mode 100644 index 6f74c5ed101..00000000000 --- a/test/integration/render-tests/fog/terrain/haze/style.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "height": 256, - "width": 256 - } - }, - "center": [-113.32296, 35.94662], - "zoom": 12.1, - "pitch": 80, - "bearing": 64.5, - "terrain": { - "source": "rgbterrain" - }, - "fog": { - "range": [1, 2], - "color": "white", - "haze-color": "rgba(0, 0, 255, 0.5)" - }, - "sources": { - "rgbterrain": { - "type": "raster-dem", - "tiles": [ - "local://tiles/{z}-{x}-{y}.terrain.png" - ], - "maxzoom": 12, - "tileSize": 256 - }, - "satellite": { - "type": "raster", - "tiles": [ - "local://tiles/{z}-{x}-{y}.satellite.png" - ], - "maxzoom": 17, - "tileSize": 256 - } - }, - "layers": [ - { - "id": "sky", - "type": "sky", - "paint": { - "sky-type": "gradient", - "sky-gradient-center": [0, 0], - "sky-gradient-radius": 90, - "sky-gradient": [ - "interpolate", - ["linear"], - ["sky-radial-progress"], - 0.0, - "#87ceeb", - 1.0, - "#87ceeb" - ] - } - }, - { - "id": "raster", - "type": "raster", - "source": "satellite", - "paint": { - "raster-fade-duration": 0 - } - } - ] -}