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

Improve sky atmosphere #8866

Merged
merged 21 commits into from
May 25, 2020
Merged
Show file tree
Hide file tree
Changes from 11 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
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@

- 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)

##### Fixes :wrench:

- Fixed a bug that could cause rendering of a glTF model to become corrupt when switching from a Uint16 to a Uint32 index buffer to accomodate new vertices added for edge outlining. [#8820](https://github.com/CesiumGS/cesium/pull/8820)
- 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
186 changes: 107 additions & 79 deletions Source/Scene/SkyAtmosphere.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ 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 Matrix3 from "../Core/Matrix3.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 +55,33 @@ 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 scaleVector = Cartesian3.multiplyByScalar(
ellipsoid.radii,
1.025,
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 +109,28 @@ 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, inverse scale
var radiiAndDynamicAtmosphereColorAndInverseScale = new Cartesian4();

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

// Toggles whether the sun position is used. 0 treats the sun as always directly overhead.
radiiAndDynamicAtmosphereColorAndInverseScale.z = 0;

// Controls the distance below the horizon at which atmosphere transitions from its brightest to a more neutral blue color
// Higher values push the transition point further below the horizon
radiiAndDynamicAtmosphereColorAndInverseScale.w = 1.003;

this._cameraAndRadiiAndDynamicAtmosphereColor = cameraAndRadiiAndDynamicAtmosphereColor;
this._radiiAndDynamicAtmosphereColorAndInverseScale = radiiAndDynamicAtmosphereColorAndInverseScale;

var that = this;

this._command.uniformMap = {
u_cameraAndRadiiAndDynamicAtmosphereColor: function () {
return that._cameraAndRadiiAndDynamicAtmosphereColor;
u_radiiAndDynamicAtmosphereColorAndInverseScale: function () {
return that._radiiAndDynamicAtmosphereColorAndInverseScale;
},
u_hsbShift: function () {
that._hueSaturationBrightness.x = that.hueShift;
Expand Down Expand Up @@ -136,13 +163,13 @@ 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._radiiAndDynamicAtmosphereColorAndInverseScale.z = lightEnum;
};

var scratchRotationMatrix = new Matrix3();
var scratchModelMatrix = new Matrix4();

/**
* @private
*/
Expand All @@ -161,18 +188,38 @@ 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 view = frameState.context.uniformState.viewRotation;
var inverseView = Matrix3.inverse(view, scratchRotationMatrix);
lilleyse marked this conversation as resolved.
Show resolved Hide resolved
var rotationMatrix = Matrix4.fromRotationTranslation(
inverseView,
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 +239,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],
});
this._spSkyFromAtmosphere = ShaderProgram.fromCache({
context: context,
vertexShaderSource: vs,
fragmentShaderSource: SkyAtmosphereFS,
defines: defines.concat("SKY_FROM_ATMOSPHERE"),
sources: [SkyAtmosphereCommon, SkyAtmosphereVS],
});
}

// 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._radiiAndDynamicAtmosphereColorAndInverseScale.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 +359,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;
Loading