Skip to content

Commit

Permalink
Merge pull request #8866 from CesiumGS/sky-atmosphere-per-fragment
Browse files Browse the repository at this point in the history
Improve sky atmosphere
  • Loading branch information
IanLilleyT authored May 25, 2020
2 parents c9dd6f6 + c157fd3 commit 565d6eb
Show file tree
Hide file tree
Showing 7 changed files with 348 additions and 292 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Added `Cesium3DTileset.extensions` to get the extensions property from the tileset JSON. [#8829](https://github.com/CesiumGS/cesium/pull/8829)
- Added `frustumSplits` option to `DebugCameraPrimitive`. [8849](https://github.com/CesiumGS/cesium/pull/8849)
- Added `SkyAtmosphere.perFragmentAtmosphere` to switch between per-vertex and per-fragment atmosphere shading. [#8866](https://github.com/CesiumGS/cesium/pull/8866)
- Added `Globe.undergroundColor` and `Globe.undergroundColorAlphaByDistance` for controlling how the back side of the globe is rendered when the camera is underground or the globe is translucent. [#8867](https://github.com/CesiumGS/cesium/pull/8867)

##### Fixes :wrench:
Expand All @@ -14,6 +15,7 @@
- Fixed a bug where a removed billboard could prevent changing of the `TerrainProvider`. [#8766](https://github.com/CesiumGS/cesium/pull/8766)
- Fixed an issue with 3D Tiles point cloud styling where `${feature.propertyName}` and `${feature["propertyName"]}` syntax would cause a crash. Also fixed an issue where property names with non-alphanumeric characters would crash. [#8785](https://github.com/CesiumGS/cesium/pull/8785)
- Fixed a bug where `DebugCameraPrimitive` was ignoring the near and far planes of the `Camera`. [#8848](https://github.com/CesiumGS/cesium/issues/8848)
- Fixed sky atmosphere artifacts below the horizon. [#8866](https://github.com/CesiumGS/cesium/pull/8866)
- Fixed ground primitives in orthographic mode. [#5110](https://github.com/CesiumGS/cesium/issues/5110)
- Fixed the depth plane in orthographic mode. This improves the quality of polylines and other primitives that are rendered near the horizon. [8858](https://github.com/CesiumGS/cesium/pull/8858)

Expand Down
181 changes: 100 additions & 81 deletions Source/Scene/SkyAtmosphere.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import Cartesian3 from "../Core/Cartesian3.js";
import Cartesian4 from "../Core/Cartesian4.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
import Ellipsoid from "../Core/Ellipsoid.js";
import EllipsoidGeometry from "../Core/EllipsoidGeometry.js";
import GeometryPipeline from "../Core/GeometryPipeline.js";
import CesiumMath from "../Core/Math.js";
import Matrix4 from "../Core/Matrix4.js";
import VertexFormat from "../Core/VertexFormat.js";
import BufferUsage from "../Renderer/BufferUsage.js";
import DrawCommand from "../Renderer/DrawCommand.js";
import RenderState from "../Renderer/RenderState.js";
import ShaderProgram from "../Renderer/ShaderProgram.js";
import ShaderSource from "../Renderer/ShaderSource.js";
import VertexArray from "../Renderer/VertexArray.js";
import SkyAtmosphereCommon from "../Shaders/SkyAtmosphereCommon.js";
import SkyAtmosphereFS from "../Shaders/SkyAtmosphereFS.js";
import SkyAtmosphereVS from "../Shaders/SkyAtmosphereVS.js";
import Axis from "./Axis.js";
import BlendingState from "./BlendingState.js";
import CullFace from "./CullFace.js";
import SceneMode from "./SceneMode.js";
Expand Down Expand Up @@ -51,15 +53,34 @@ function SkyAtmosphere(ellipsoid) {
*/
this.show = true;

/**
* Compute atmosphere per-fragment instead of per-vertex.
* This produces better looking atmosphere with a slight performance penalty.
*
* @type {Boolean}
* @default false
*/
this.perFragmentAtmosphere = false;

this._ellipsoid = ellipsoid;

var outerEllipsoidScale = 1.025;
var scaleVector = Cartesian3.multiplyByScalar(
ellipsoid.radii,
outerEllipsoidScale,
new Cartesian3()
);
this._scaleMatrix = Matrix4.fromScale(scaleVector);
this._modelMatrix = new Matrix4();

this._command = new DrawCommand({
owner: this,
modelMatrix: this._modelMatrix,
});
this._spSkyFromSpace = undefined;
this._spSkyFromAtmosphere = undefined;

this._spSkyFromSpaceColorCorrect = undefined;
this._spSkyFromAtmosphereColorCorrect = undefined;
this._flags = undefined;

/**
* The hue shift to apply to the atmosphere. Defaults to 0.0 (no shift).
Expand Down Expand Up @@ -87,23 +108,23 @@ function SkyAtmosphere(ellipsoid) {

this._hueSaturationBrightness = new Cartesian3();

// camera height, outer radius, inner radius, dynamic atmosphere color flag
var cameraAndRadiiAndDynamicAtmosphereColor = new Cartesian4();
// outer radius, inner radius, dynamic atmosphere color flag
var radiiAndDynamicAtmosphereColor = new Cartesian3();

radiiAndDynamicAtmosphereColor.x =
ellipsoid.maximumRadius * outerEllipsoidScale;
radiiAndDynamicAtmosphereColor.y = ellipsoid.maximumRadius;

// Toggles whether the sun position is used. 0 treats the sun as always directly overhead.
cameraAndRadiiAndDynamicAtmosphereColor.w = 0;
cameraAndRadiiAndDynamicAtmosphereColor.y = Cartesian3.maximumComponent(
Cartesian3.multiplyByScalar(ellipsoid.radii, 1.025, new Cartesian3())
);
cameraAndRadiiAndDynamicAtmosphereColor.z = ellipsoid.maximumRadius;
radiiAndDynamicAtmosphereColor.z = 0;

this._cameraAndRadiiAndDynamicAtmosphereColor = cameraAndRadiiAndDynamicAtmosphereColor;
this._radiiAndDynamicAtmosphereColor = radiiAndDynamicAtmosphereColor;

var that = this;

this._command.uniformMap = {
u_cameraAndRadiiAndDynamicAtmosphereColor: function () {
return that._cameraAndRadiiAndDynamicAtmosphereColor;
u_radiiAndDynamicAtmosphereColor: function () {
return that._radiiAndDynamicAtmosphereColor;
},
u_hsbShift: function () {
that._hueSaturationBrightness.x = that.hueShift;
Expand Down Expand Up @@ -136,13 +157,12 @@ SkyAtmosphere.prototype.setDynamicAtmosphereColor = function (
enableLighting,
useSunDirection
) {
this._cameraAndRadiiAndDynamicAtmosphereColor.w = enableLighting
? useSunDirection
? 2.0
: 1.0
: 0.0;
var lightEnum = enableLighting ? (useSunDirection ? 2.0 : 1.0) : 0.0;
this._radiiAndDynamicAtmosphereColor.z = lightEnum;
};

var scratchModelMatrix = new Matrix4();

/**
* @private
*/
Expand All @@ -161,18 +181,36 @@ SkyAtmosphere.prototype.update = function (frameState) {
return undefined;
}

// Align the ellipsoid geometry so it always faces the same direction as the
// camera to reduce artifacts when rendering atmosphere per-vertex
var rotationMatrix = Matrix4.fromRotationTranslation(
frameState.context.uniformState.inverseViewRotation,
Cartesian3.ZERO,
scratchModelMatrix
);
var rotationOffsetMatrix = Matrix4.multiplyTransformation(
rotationMatrix,
Axis.Y_UP_TO_Z_UP,
scratchModelMatrix
);
var modelMatrix = Matrix4.multiply(
this._scaleMatrix,
rotationOffsetMatrix,
scratchModelMatrix
);
Matrix4.clone(modelMatrix, this._modelMatrix);

var context = frameState.context;

var colorCorrect = hasColorCorrection(this);
var perFragmentAtmosphere = this.perFragmentAtmosphere;

var command = this._command;

if (!defined(command.vertexArray)) {
var context = frameState.context;

var geometry = EllipsoidGeometry.createGeometry(
new EllipsoidGeometry({
radii: Cartesian3.multiplyByScalar(
this._ellipsoid.radii,
1.025,
new Cartesian3()
),
radii: new Cartesian3(1.0, 1.0, 1.0),
slicePartitions: 256,
stackPartitions: 256,
vertexFormat: VertexFormat.POSITION_ONLY,
Expand All @@ -192,84 +230,71 @@ SkyAtmosphere.prototype.update = function (frameState) {
blending: BlendingState.ALPHA_BLEND,
depthMask: false,
});
}

var flags = colorCorrect | (perFragmentAtmosphere << 2);

if (flags !== this._flags) {
this._flags = flags;

var defines = [];

if (colorCorrect) {
defines.push("COLOR_CORRECT");
}

if (perFragmentAtmosphere) {
defines.push("PER_FRAGMENT_ATMOSPHERE");
}

var vs = new ShaderSource({
defines: ["SKY_FROM_SPACE"],
sources: [SkyAtmosphereVS],
defines: defines.concat("SKY_FROM_SPACE"),
sources: [SkyAtmosphereCommon, SkyAtmosphereVS],
});

var fs = new ShaderSource({
defines: defines.concat("SKY_FROM_SPACE"),
sources: [SkyAtmosphereCommon, SkyAtmosphereFS],
});

this._spSkyFromSpace = ShaderProgram.fromCache({
context: context,
vertexShaderSource: vs,
fragmentShaderSource: SkyAtmosphereFS,
fragmentShaderSource: fs,
});

vs = new ShaderSource({
defines: ["SKY_FROM_ATMOSPHERE"],
sources: [SkyAtmosphereVS],
defines: defines.concat("SKY_FROM_ATMOSPHERE"),
sources: [SkyAtmosphereCommon, SkyAtmosphereVS],
});
this._spSkyFromAtmosphere = ShaderProgram.fromCache({
context: context,
vertexShaderSource: vs,
fragmentShaderSource: SkyAtmosphereFS,
});
}

// Compile the color correcting versions of the shader on demand
var useColorCorrect = colorCorrect(this);
if (
useColorCorrect &&
(!defined(this._spSkyFromSpaceColorCorrect) ||
!defined(this._spSkyFromAtmosphereColorCorrect))
) {
var contextColorCorrect = frameState.context;

var vsColorCorrect = new ShaderSource({
defines: ["SKY_FROM_SPACE"],
sources: [SkyAtmosphereVS],
});
var fsColorCorrect = new ShaderSource({
defines: ["COLOR_CORRECT"],
sources: [SkyAtmosphereFS],
fs = new ShaderSource({
defines: defines.concat("SKY_FROM_ATMOSPHERE"),
sources: [SkyAtmosphereCommon, SkyAtmosphereFS],
});

this._spSkyFromSpaceColorCorrect = ShaderProgram.fromCache({
context: contextColorCorrect,
vertexShaderSource: vsColorCorrect,
fragmentShaderSource: fsColorCorrect,
});
vsColorCorrect = new ShaderSource({
defines: ["SKY_FROM_ATMOSPHERE"],
sources: [SkyAtmosphereVS],
});
this._spSkyFromAtmosphereColorCorrect = ShaderProgram.fromCache({
context: contextColorCorrect,
vertexShaderSource: vsColorCorrect,
fragmentShaderSource: fsColorCorrect,
this._spSkyFromAtmosphere = ShaderProgram.fromCache({
context: context,
vertexShaderSource: vs,
fragmentShaderSource: fs,
});
}

var cameraPosition = frameState.camera.positionWC;

var cameraHeight = Cartesian3.magnitude(cameraPosition);
this._cameraAndRadiiAndDynamicAtmosphereColor.x = cameraHeight;

if (cameraHeight > this._cameraAndRadiiAndDynamicAtmosphereColor.y) {
if (cameraHeight > this._radiiAndDynamicAtmosphereColor.x) {
// Camera in space
command.shaderProgram = useColorCorrect
? this._spSkyFromSpaceColorCorrect
: this._spSkyFromSpace;
command.shaderProgram = this._spSkyFromSpace;
} else {
// Camera in atmosphere
command.shaderProgram = useColorCorrect
? this._spSkyFromAtmosphereColorCorrect
: this._spSkyFromAtmosphere;
command.shaderProgram = this._spSkyFromAtmosphere;
}

return command;
};

function colorCorrect(skyAtmosphere) {
function hasColorCorrection(skyAtmosphere) {
return !(
CesiumMath.equalsEpsilon(
skyAtmosphere.hueShift,
Expand Down Expand Up @@ -325,12 +350,6 @@ SkyAtmosphere.prototype.destroy = function () {
this._spSkyFromSpace = this._spSkyFromSpace && this._spSkyFromSpace.destroy();
this._spSkyFromAtmosphere =
this._spSkyFromAtmosphere && this._spSkyFromAtmosphere.destroy();
this._spSkyFromSpaceColorCorrect =
this._spSkyFromSpaceColorCorrect &&
this._spSkyFromSpaceColorCorrect.destroy();
this._spSkyFromAtmosphereColorCorrect =
this._spSkyFromAtmosphereColorCorrect &&
this._spSkyFromAtmosphereColorCorrect.destroy();
return destroyObject(this);
};
export default SkyAtmosphere;
4 changes: 2 additions & 2 deletions Source/Shaders/GlobeFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ vec3 computeGroundAtmosphereColor(vec3 fogColor, vec4 finalColor, vec3 atmospher
groundAtmosphereColor = vec3(1.0) - exp(-fExposure * groundAtmosphereColor);
#endif

fadeInDist = u_nightFadeDistance.x;
fadeOutDist = u_nightFadeDistance.y;
float fadeInDist = u_nightFadeDistance.x;
float fadeOutDist = u_nightFadeDistance.y;

float sunlitAtmosphereIntensity = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0);

Expand Down
Loading

0 comments on commit 565d6eb

Please sign in to comment.