Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ground atmosphere and day/night shading to Model and 3D Tiles #11765

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- The `Cesium3DTileset.dynamicScreenSpaceError` optimization is now enabled by default, as this improves performance for street-level horizon views. Furthermore, the default settings of this feature were tuned for improved performance. `Cesium3DTileset.dynamicScreenSpaceErrorDensity` was changed from 0.00278 to 0.0002. `Cesium3DTileset.dynamicScreenSpaceErrorFactor` was changed from 4 to 24. [#11718](https://github.com/CesiumGS/cesium/pull/11718)
- Fog rendering now applies to glTF models and 3D Tiles. This can be configured using `scene.fog` and `scene.atmosphere`. [#11744](https://github.com/CesiumGS/cesium/pull/11744)
- Added `scene.atmosphere` to store common atmosphere lighting parameters. [#11744](https://github.com/CesiumGS/cesium/pull/11744) and [#11681](https://github.com/CesiumGS/cesium/issues/11681)
- Added ground atmosphere to glTF models and 3D Tiles. This can be toggled with `scene.atmosphere.showGroundAtmosphere`. [#11765](https://github.com/CesiumGS/cesium/pull/11765)

##### Fixes :wrench:

Expand Down
30 changes: 30 additions & 0 deletions packages/engine/Source/Renderer/AutomaticUniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,36 @@ const AutomaticUniforms = {
},
}),

/**
* An automatic uniform representing the range of camera distances used for
* fading in ground atmosphere lighting.
*
* @example
* uniform vec2 czm_atmosphereLightingFadeRange
*/
czm_atmosphereLightingFadeRange: new AutomaticUniform({
size: 1,
datatype: WebGLConstants.FLOAT_VEC2,
getValue: function (uniformState) {
return uniformState.atmosphereLightingFadeRange;
},
}),

/**
* An automatic uniform representing the range of camera distances used for
* fading in night time shading.
*
* @example
* uniform vec2 czm_atmosphereNightFadeRange
*/
czm_atmosphereNightFadeRange: new AutomaticUniform({
size: 1,
datatype: WebGLConstants.FLOAT_VEC2,
getValue: function (uniformState) {
return uniformState.atmosphereNightFadeRange;
},
}),

/**
* An automatic GLSL uniform representing the splitter position to use when rendering with a splitter.
* This will be in pixel coordinates relative to the canvas.
Expand Down
38 changes: 38 additions & 0 deletions packages/engine/Source/Renderer/UniformState.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ function UniformState() {
this._atmosphereMieAnisotropy = undefined;
this._atmosphereDynamicLighting = undefined;

// (fadeOutDistance, fadeInDistance)
this._atmosphereLightingFadeRange = new Cartesian2();
this._atmosphereNightFadeRange = new Cartesian2();

this._invertClassificationColor = undefined;

this._splitPosition = 0.0;
Expand Down Expand Up @@ -946,6 +950,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereHsbShift;
},
},

/**
* The intensity of the light that is used for computing the atmosphere color
* @memberof UniformState.prototype
Expand All @@ -956,6 +961,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereLightIntensity;
},
},

/**
* The Rayleigh scattering coefficient used in the atmospheric scattering equations for the sky atmosphere.
* @memberof UniformState.prototype
Expand All @@ -966,6 +972,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereRayleighCoefficient;
},
},

/**
* The Rayleigh scale height used in the atmospheric scattering equations for the sky atmosphere, in meters.
* @memberof UniformState.prototype
Expand All @@ -976,6 +983,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereRayleighScaleHeight;
},
},

/**
* The Mie scattering coefficient used in the atmospheric scattering equations for the sky atmosphere.
* @memberof UniformState.prototype
Expand All @@ -986,6 +994,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereMieCoefficient;
},
},

/**
* The Mie scale height used in the atmospheric scattering equations for the sky atmosphere, in meters.
* @memberof UniformState.prototype
Expand All @@ -996,6 +1005,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereMieScaleHeight;
},
},

/**
* The anisotropy of the medium to consider for Mie scattering.
* @memberof UniformState.prototype
Expand All @@ -1006,6 +1016,7 @@ Object.defineProperties(UniformState.prototype, {
return this._atmosphereMieAnisotropy;
},
},

/**
* Which light source to use for dynamically lighting the atmosphere
*
Expand All @@ -1018,6 +1029,30 @@ Object.defineProperties(UniformState.prototype, {
},
},

/**
* The range of camera distances between which atmosphere lighting fades in/out
*
* @memberof UniformState.prototype
* @type {Cartesian2}
*/
atmosphereLightingFadeRange: {
get: function () {
return this._atmosphereLightingFadeRange;
},
},

/**
* The range of camera distances between which day/night shading fades in/out
*
* @memberof UniformState.prototype
* @type {Cartesian2}
*/
atmosphereNightFadeRange: {
get: function () {
return this._atmosphereNightFadeRange;
},
},

/**
* A scalar that represents the geometric tolerance per meter
* @memberof UniformState.prototype
Expand Down Expand Up @@ -1537,6 +1572,9 @@ UniformState.prototype.update = function (frameState) {
this._atmosphereMieScaleHeight = atmosphere.mieScaleHeight;
this._atmosphereMieAnisotropy = atmosphere.mieAnisotropy;
this._atmosphereDynamicLighting = atmosphere.dynamicLighting;

this._atmosphereLightingFadeRange = atmosphere.lightingFadeRange;
this._atmosphereNightFadeRange = atmosphere.nightFadeRange;
}

this._invertClassificationColor = frameState.invertClassificationColor;
Expand Down
55 changes: 54 additions & 1 deletion packages/engine/Source/Scene/Atmosphere.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Cartesian2 from "../Core/Cartesian2.js";
import Cartesian3 from "../Core/Cartesian3.js";
import DynamicAtmosphereLightingType from "./DynamicAtmosphereLightingType.js";

Expand Down Expand Up @@ -31,6 +32,10 @@ import DynamicAtmosphereLightingType from "./DynamicAtmosphereLightingType.js";
* scene.atmosphere.brightnessShift = 0.25; // Increase the brightness
* scene.atmosphere.saturationShift = -0.1; // Desaturate the colors
*
* @example
* // Turn off ground atmosphere
* scene.atmosphere.showGroundAtmosphere = false;
*
* @see SkyAtmosphere
* @see Globe
* @see Fog
Expand Down Expand Up @@ -115,13 +120,61 @@ function Atmosphere() {
this.brightnessShift = 0.0;

/**
* When not DynamicAtmosphereLightingType.NONE, the selected light source will
* When not {@link DynamicAtmosphereLightingType.NONE}, the selected light source will
* be used for dynamically lighting all atmosphere-related rendering effects.
*
* @type {DynamicAtmosphereLightingType}
* @default DynamicAtmosphereLightingType.NONE
*/
this.dynamicLighting = DynamicAtmosphereLightingType.NONE;

/**
* The range of camera distances <code>[startDist, endDist]</code>
* between which ground atmosphere lighting fades in. When the camera is at or
* below startDist, no ground atmosphere lighting is applied. When the camera
* is at or above endDist,the lighting is at maximum intensity.
* <p>
* Ground atmosphere lighting only applies when {@link Atmosphere#showGroundAtmosphere}
* is <code>true.</code>
* </p>
* <p>
* Camera distances are measured from the center of the earth in meters.
* </p>
*
* @type {Cartesian2}
* @default Cartesian2(1.0e7, 2.0e7)
*/
this.lightingFadeRange = new Cartesian2(1.0e7, 2.0e7);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to @ggetz and @jjhembd: this parameter is a rephrasing of the confusingly-named parameters [globe.lightingFadeOutDistance, globe.lightingFadeInDistance], I figured this way would be easier to explain to users.

/**
* The range of camera distances <code>[startDist, endDist]</code>
* between which nighttime shading fades in. When the camera is at or below
* startDist, the entire globe is lit at full brightness. When the camera is
* at or above endDist, the side of the globe facing away from the sun
* will be in total darkness.
* <p>
* Nighttime shading only applies when {@link Atmosphere#showGroundAtmosphere}
* is <code>true</code>, and {@link Atmosphere#dynamicLighting} is not {@link DynamicAtmosphereLightingType.NONE}.
* </p>
* <p>
* Camera distances are measured from the center of the earth in meters.
* </p>
*
* @type {Cartesian2}
* @default Cartesian2(5.0e7, 1.0e7)
*/
this.nightFadeRange = new Cartesian2(1.0e7, 5.0e7);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, this is a rephrasing of [globe.nightFadeOutDistance, globe.nightFadeInDistance]


/**
* Enable the ground atmosphere for 3D Tiles and models. The ground atmosphere
* is drawn over the globe when viewed from a distance between
* <code>lightingFadeInDistance</code> and <code>lightingFadeOutDistance</code>.
* The ground atmosphere makes the globe's surface appear brighter near the
* edges when viewed from space.
*
* @type {boolean}
* @default true
*/
this.showGroundAtmosphere = true;
}

export default Atmosphere;
52 changes: 52 additions & 0 deletions packages/engine/Source/Scene/Model/AtmospherePipelineStage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Cartesian3 from "../../Core/Cartesian3.js";
import CesiumMath from "../../Core/Math.js";
import defined from "../../Core/defined.js";
import ShaderDestination from "../../Renderer/ShaderDestination.js";
import AtmosphereStageFS from "../../Shaders/Model/AtmosphereStageFS.js";
import AtmosphereStageVS from "../../Shaders/Model/AtmosphereStageVS.js";
Expand Down Expand Up @@ -43,6 +44,11 @@ AtmospherePipelineStage.process = function (
// 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 () {
const fogRenderable = frameState.fog.enabled && frameState.fog.renderable;
if (!fogRenderable) {
return false;
}

// 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(
Expand All @@ -54,6 +60,52 @@ AtmospherePipelineStage.process = function (
CesiumMath.fog(distance, frameState.fog.density) > CesiumMath.EPSILON3
);
};

// When the camera is near the earth, compute the atmosphere scattering
// in the vertex shader for performance. When the camera is far away,
// compute it in the fragment shader instead for better accuracy
shaderBuilder.addUniform(
"bool",
"u_perFragmentGroundAtmosphere",
ShaderDestination.BOTH
);
renderResources.uniformMap.u_perFragmentGroundAtmosphere = function () {
if (!defined(frameState.atmosphere)) {
return false;
}

const cameraDistance = Cartesian3.magnitude(frameState.camera.positionWC);
const nightFadeStart = frameState.atmosphere.nightFadeRange.x;
return cameraDistance > nightFadeStart;
};

// Only apply the color correction math in the shader if one of the
// HSB color shift options are set.
shaderBuilder.addUniform(
"bool",
"u_shouldColorCorrect",
ShaderDestination.FRAGMENT
);
renderResources.uniformMap.u_shouldColorCorrect = function () {
const atmosphere = frameState.atmosphere;
if (!defined(atmosphere)) {
return false;
}

return !(
CesiumMath.equalsEpsilon(atmosphere.hueShift, 0.0, CesiumMath.EPSILON7) &&
CesiumMath.equalsEpsilon(
atmosphere.saturationShift,
0.0,
CesiumMath.EPSILON7
) &&
CesiumMath.equalsEpsilon(
atmosphere.brightnessShift,
0.0,
CesiumMath.EPSILON7
)
);
};
};

export default AtmospherePipelineStage;
14 changes: 9 additions & 5 deletions packages/engine/Source/Scene/Model/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ function Model(options) {
this._projectTo2D = defaultValue(options.projectTo2D, false);
this._enablePick = defaultValue(options.enablePick, false);

this._fogRenderable = undefined;
this._atmosphereEffectsEnabled = undefined;

this._skipLevelOfDetail = false;
this._ignoreCommands = defaultValue(options.ignoreCommands, false);
Expand Down Expand Up @@ -1800,7 +1800,7 @@ Model.prototype.update = function (frameState) {
updateSkipLevelOfDetail(this, frameState);
updateClippingPlanes(this, frameState);
updateSceneMode(this, frameState);
updateFog(this, frameState);
updateAtmosphereEffects(this, frameState);
updateVerticalExaggeration(this, frameState);

this._defaultTexture = frameState.context.defaultTexture;
Expand Down Expand Up @@ -1996,11 +1996,15 @@ function updateSceneMode(model, frameState) {
}
}

function updateFog(model, frameState) {
function updateAtmosphereEffects(model, frameState) {
// The AtmospherePipelineStage handles both fog and ground atmosphere.
// It is enabled when at least one of these two features is enabled.
const fogRenderable = frameState.fog.enabled && frameState.fog.renderable;
if (fogRenderable !== model._fogRenderable) {
const showGroundAtmosphere = frameState.atmosphere.showGroundAtmosphere;
const atmosphereEffectsEnabled = fogRenderable || showGroundAtmosphere;
if (atmosphereEffectsEnabled !== model._atmosphereEffectsEnabled) {
model.resetDrawCommands();
model._fogRenderable = fogRenderable;
model._atmosphereEffectsEnabled = atmosphereEffectsEnabled;
}
}

Expand Down
4 changes: 3 additions & 1 deletion packages/engine/Source/Scene/Model/ModelSceneGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,8 @@ ModelSceneGraph.prototype.configurePipeline = function (frameState) {

const model = this._model;
const fogRenderable = frameState.fog.enabled && frameState.fog.renderable;
const showGroundAtmosphere = frameState.atmosphere.showGroundAtmosphere;
const atmosphereEnabled = fogRenderable || showGroundAtmosphere;

if (defined(model.color)) {
modelPipelineStages.push(ModelColorPipelineStage);
Expand Down Expand Up @@ -641,7 +643,7 @@ ModelSceneGraph.prototype.configurePipeline = function (frameState) {
modelPipelineStages.push(TilesetPipelineStage);
}

if (fogRenderable) {
if (atmosphereEnabled) {
modelPipelineStages.push(AtmospherePipelineStage);
}
};
Expand Down
Loading