diff --git a/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js b/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js index e32b797efc48..a6851b02e469 100644 --- a/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js +++ b/packages/engine/Source/Scene/GlobeSurfaceTileProvider.js @@ -2502,7 +2502,9 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { uniformMapProperties.localizedTranslucencyRectangle ); - // For performance, use fog in the shader only when the tile is in fog. + // For performance, render fog only when fog is enabled and the effect of + // fog would be non-negligible. This prevents the shader from running when + // the camera is in space, for example. const applyFog = enableFog && CesiumMath.fog(tile._distance, frameState.fog.density) > diff --git a/packages/engine/Source/Scene/Model/FogPipelineStage.js b/packages/engine/Source/Scene/Model/FogPipelineStage.js index 09b72fedf068..2907582f07ad 100644 --- a/packages/engine/Source/Scene/Model/FogPipelineStage.js +++ b/packages/engine/Source/Scene/Model/FogPipelineStage.js @@ -1,5 +1,7 @@ -import FogStageFS from "../../Shaders/Model/FogStageFS.js"; +import Cartesian3 from "../../Core/Cartesian3.js"; +import CesiumMath from "../../Core/Math.js"; import ShaderDestination from "../../Renderer/ShaderDestination.js"; +import FogStageFS from "../../Shaders/Model/FogStageFS.js"; /** * The fog color pipeline stage is responsible for applying fog to tiles in the distance in horizon views. @@ -17,6 +19,24 @@ FogPipelineStage.process = function (renderResources, model, frameState) { shaderBuilder.addDefine("HAS_FOG", undefined, ShaderDestination.FRAGMENT); shaderBuilder.addFragmentLines([FogStageFS]); + + // Add a uniform so fog is only calculated when the effect would + // be non-negligible For example when the camera is in space, fog density decreases + // to 0 so fog shouldn't be rendered. Since this state may change rapidly if + // the camera is moving, this is implemented as a uniform, not a define. + shaderBuilder.addUniform("bool", "u_isInFog", ShaderDestination.FRAGMENT); + renderResources.uniformMap.u_isInFog = function () { + // We only need a rough measure of distance to the model, so measure + // from the camera to the bounding sphere center. + const distance = Cartesian3.distance( + frameState.camera.position, + model.boundingSphere.center + ); + + return ( + CesiumMath.fog(distance, frameState.fog.density) > CesiumMath.EPSILON3 + ); + }; }; export default FogPipelineStage; diff --git a/packages/engine/Source/Scene/Model/ModelRuntimePrimitive.js b/packages/engine/Source/Scene/Model/ModelRuntimePrimitive.js index e168b6b280e8..ed82ca255cf4 100644 --- a/packages/engine/Source/Scene/Model/ModelRuntimePrimitive.js +++ b/packages/engine/Source/Scene/Model/ModelRuntimePrimitive.js @@ -11,7 +11,6 @@ import CustomShaderMode from "./CustomShaderMode.js"; import CustomShaderPipelineStage from "./CustomShaderPipelineStage.js"; import DequantizationPipelineStage from "./DequantizationPipelineStage.js"; import FeatureIdPipelineStage from "./FeatureIdPipelineStage.js"; -import FogPipelineStage from "./FogPipelineStage.js"; import GeometryPipelineStage from "./GeometryPipelineStage.js"; import LightingPipelineStage from "./LightingPipelineStage.js"; import MaterialPipelineStage from "./MaterialPipelineStage.js"; @@ -200,7 +199,6 @@ ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) { const mode = frameState.mode; const use2D = mode !== SceneMode.SCENE3D && !frameState.scene3DOnly && model._projectTo2D; - const fogRenderable = frameState.fog.enabled && frameState.fog.renderable; const exaggerateTerrain = frameState.verticalExaggeration !== 1.0; const hasMorphTargets = @@ -305,10 +303,6 @@ ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) { pipelineStages.push(AlphaPipelineStage); - if (fogRenderable) { - pipelineStages.push(FogPipelineStage); - } - pipelineStages.push(PrimitiveStatisticsPipelineStage); return; diff --git a/packages/engine/Source/Scene/Model/ModelSceneGraph.js b/packages/engine/Source/Scene/Model/ModelSceneGraph.js index 1ff305d3adcf..72e3cbf11d7b 100644 --- a/packages/engine/Source/Scene/Model/ModelSceneGraph.js +++ b/packages/engine/Source/Scene/Model/ModelSceneGraph.js @@ -9,6 +9,7 @@ import SceneMode from "../SceneMode.js"; import SplitDirection from "../SplitDirection.js"; import buildDrawCommand from "./buildDrawCommand.js"; import TilesetPipelineStage from "./TilesetPipelineStage.js"; +import FogPipelineStage from "./FogPipelineStage.js"; import ImageBasedLightingPipelineStage from "./ImageBasedLightingPipelineStage.js"; import ModelArticulation from "./ModelArticulation.js"; import ModelColorPipelineStage from "./ModelColorPipelineStage.js"; @@ -606,6 +607,7 @@ ModelSceneGraph.prototype.configurePipeline = function (frameState) { modelPipelineStages.length = 0; const model = this._model; + const fogRenderable = frameState.fog.enabled && frameState.fog.renderable; if (defined(model.color)) { modelPipelineStages.push(ModelColorPipelineStage); @@ -638,6 +640,10 @@ ModelSceneGraph.prototype.configurePipeline = function (frameState) { if (ModelType.is3DTiles(model.type)) { modelPipelineStages.push(TilesetPipelineStage); } + + if (fogRenderable) { + modelPipelineStages.push(FogPipelineStage); + } }; ModelSceneGraph.prototype.update = function (frameState, updateForAnimations) { diff --git a/packages/engine/Source/Shaders/GlobeFS.glsl b/packages/engine/Source/Shaders/GlobeFS.glsl index 79d5960159ee..3d181e60ee0c 100644 --- a/packages/engine/Source/Shaders/GlobeFS.glsl +++ b/packages/engine/Source/Shaders/GlobeFS.glsl @@ -523,8 +523,6 @@ void main() finalColor.rgb = mix(finalColor.rgb, finalAtmosphereColor.rgb, fade); #endif - - //finalColor.rgb = computeEllipsoidPosition() / 1e7; } #endif diff --git a/packages/engine/Source/Shaders/Model/FogStageFS.glsl b/packages/engine/Source/Shaders/Model/FogStageFS.glsl index a6c6fa74d652..5d319ded73e7 100644 --- a/packages/engine/Source/Shaders/Model/FogStageFS.glsl +++ b/packages/engine/Source/Shaders/Model/FogStageFS.glsl @@ -76,6 +76,12 @@ vec3 computeFogColor(vec3 positionMC) { } void fogStage(inout vec4 color, in ProcessedAttributes attributes) { + if (!u_isInFog) { + // Debugging + //color.rgb = vec3(1.0, 1.0, 0.0); + return; + } + vec3 fogColor = computeFogColor(attributes.positionMC); // Note: camera is far away (distance > nightFadeOutDistance), scattering is computed in the fragment shader.