From f6a9d6ff8554755c32b0dbd6f589acfe34637cdd Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Sun, 17 May 2020 19:55:13 -0400 Subject: [PATCH 01/13] Add underground color --- CHANGES.md | 1 + Source/Scene/Globe.js | 37 +++++++++++++++ Source/Scene/GlobeSurfaceShaderSet.js | 9 +++- Source/Scene/GlobeSurfaceTileProvider.js | 39 ++++++++++++++++ Source/Shaders/GlobeFS.glsl | 39 +++++++++++++++- Source/Shaders/GlobeVS.glsl | 8 +++- Specs/Scene/GlobeSpec.js | 57 ++++++++++++++++++++++++ 7 files changed, 186 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5e7b0392c1d3..399b835c13ee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 `Globe.undergroundColor` and `Globe.undergroundColorByDistance` for controlling how the back side of the globe is rendered when the camera is underground or the globe is translucent. ##### Fixes :wrench: diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js index 39dbb29d9496..71abb53ce05b 100644 --- a/Source/Scene/Globe.js +++ b/Source/Scene/Globe.js @@ -2,6 +2,7 @@ import BoundingSphere from "../Core/BoundingSphere.js"; import buildModuleUrl from "../Core/buildModuleUrl.js"; import Cartesian3 from "../Core/Cartesian3.js"; import Cartographic from "../Core/Cartographic.js"; +import Color from "../Core/Color.js"; import defaultValue from "../Core/defaultValue.js"; import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; @@ -10,6 +11,7 @@ import Ellipsoid from "../Core/Ellipsoid.js"; import EllipsoidTerrainProvider from "../Core/EllipsoidTerrainProvider.js"; import Event from "../Core/Event.js"; import IntersectionTests from "../Core/IntersectionTests.js"; +import NearFarScalar from "../Core/NearFarScalar.js"; import Ray from "../Core/Ray.js"; import Rectangle from "../Core/Rectangle.js"; import Resource from "../Core/Resource.js"; @@ -60,6 +62,39 @@ function Globe(ellipsoid) { this._terrainProvider = terrainProvider; this._terrainProviderChanged = new Event(); + /** + * The color to render the back side of the globe when the camera is underground or the globe is translucent, + * blended with the globe color based on the camera's distance. + *

+ * To disable underground coloring, set undergroundColor to undefined. + * + * @type {Color} + * @default {@link Color.BLACK} + * + * @see Globe#undergroundColorByDistance + */ + this.undergroundColor = Color.clone(Color.BLACK); + + /** + * Gets or sets the near and far distance for blending {@link Globe#undergroundColor} with the globe color. + * The blending amount will interpolate between the {@link NearFarScalar#nearValue} and + * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds + * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. + * Outside of these ranges the blending amount remains clamped to the nearest bound. If undefined, + * the underground color will not be blended with the globe color. + * + * @type {NearFarScalar} + * + * @see Globe#undergroundColor + * + */ + this.undergroundColorByDistance = new NearFarScalar( + ellipsoid.maximumRadius / 1000.0, + 0.0, + ellipsoid.maximumRadius / 5.0, + 1.0 + ); + makeShadersDirty(this); /** @@ -868,6 +903,8 @@ Globe.prototype.beginFrame = function (frameState) { tileProvider.fillHighlightColor = this.fillHighlightColor; tileProvider.showSkirts = this.showSkirts; tileProvider.backFaceCulling = this.backFaceCulling; + tileProvider.undergroundColor = this.undergroundColor; + tileProvider.undergroundColorByDistance = this.undergroundColorByDistance; surface.beginFrame(frameState); } }; diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js index c96f89c2a6ac..fc5968716125 100644 --- a/Source/Scene/GlobeSurfaceShaderSet.js +++ b/Source/Scene/GlobeSurfaceShaderSet.js @@ -99,6 +99,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { var colorCorrect = options.colorCorrect; var highlightFillTile = options.highlightFillTile; var colorToAlpha = options.colorToAlpha; + var showUndergroundColor = options.showUndergroundColor; var quantization = 0; var quantizationDefine = ""; @@ -151,7 +152,8 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { (imageryCutoutFlag << 22) | (colorCorrect << 23) | (highlightFillTile << 24) | - (colorToAlpha << 25); + (colorToAlpha << 25) | + (showUndergroundColor << 26); var currentClippingShaderState = 0; if (defined(clippingPlanes) && clippingPlanes.length > 0) { @@ -227,7 +229,10 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) { if (colorToAlpha) { fs.defines.push("APPLY_COLOR_TO_ALPHA"); } - + if (showUndergroundColor) { + vs.defines.push("UNDERGROUND_COLOR"); + fs.defines.push("UNDERGROUND_COLOR"); + } if (enableLighting) { if (hasVertexNormals) { vs.defines.push("ENABLE_VERTEX_LIGHTING"); diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 2f43ecd92c3a..231fbc36fe4f 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -19,6 +19,7 @@ import IndexDatatype from "../Core/IndexDatatype.js"; import Intersect from "../Core/Intersect.js"; import CesiumMath from "../Core/Math.js"; import Matrix4 from "../Core/Matrix4.js"; +import NearFarScalar from "../Core/NearFarScalar.js"; import OrientedBoundingBox from "../Core/OrientedBoundingBox.js"; import OrthographicFrustum from "../Core/OrthographicFrustum.js"; import PrimitiveType from "../Core/PrimitiveType.js"; @@ -104,6 +105,8 @@ function GlobeSurfaceTileProvider(options) { this.showSkirts = true; this.backFaceCulling = true; + this.undergroundColor = undefined; + this.undergroundColorByDistance = undefined; this._quadtree = undefined; this._terrainProvider = options.terrainProvider; @@ -1584,6 +1587,12 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) { u_colorsToAlpha: function () { return this.properties.colorsToAlpha; }, + u_undergroundColor: function () { + return this.properties.undergroundColor; + }, + u_undergroundColorByDistance: function () { + return this.properties.undergroundColorByDistance; + }, // make a separate object so that changes to the properties are seen on // derived commands that combine another uniform map with this one. @@ -1628,6 +1637,9 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) { clippingPlanesEdgeWidth: 0.0, localizedCartographicLimitRectangle: new Cartesian4(), + + undergroundColor: Color.clone(Color.TRANSPARENT), + undergroundColorByDistance: new Cartesian4(), }, }; @@ -1821,6 +1833,8 @@ var surfaceShaderSetOptionsScratch = { colorToAlpha: undefined, }; +var defaultUndergroundColorByDistance = new NearFarScalar(); + function addDrawCommandsForTile(tileProvider, tile, frameState) { var surfaceTile = tile.data; @@ -1860,6 +1874,21 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { var cameraUnderground = frameState.cameraUnderground; + var undergroundColor = defaultValue( + tileProvider.undergroundColor, + Color.TRANSPARENT + ); + var undergroundColorByDistance = defaultValue( + tileProvider.undergroundColorByDistance, + defaultUndergroundColorByDistance + ); + var showUndergroundColor = + cameraUnderground && + frameState.mode === SceneMode.SCENE3D && + undergroundColor.alpha > 0.0 && + (undergroundColorByDistance.nearValue > 0.0 || + undergroundColorByDistance.farValue > 0.0); + var showReflectiveOcean = tileProvider.hasWaterMask && defined(waterMaskTexture); var oceanNormalMap = tileProvider.oceanNormalMap; @@ -2087,6 +2116,15 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { uniformMapProperties.zoomedOutOceanSpecularIntensity = tileProvider.zoomedOutOceanSpecularIntensity; + Cartesian4.fromElements( + undergroundColorByDistance.near, + undergroundColorByDistance.nearValue, + undergroundColorByDistance.far, + undergroundColorByDistance.farValue, + uniformMapProperties.undergroundColorByDistance + ); + Color.clone(undergroundColor, uniformMapProperties.undergroundColor); + var highlightFillTile = !defined(surfaceTile.vertexArray) && defined(tileProvider.fillHighlightColor) && @@ -2370,6 +2408,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { surfaceShaderSetOptions.colorCorrect = colorCorrect; surfaceShaderSetOptions.highlightFillTile = highlightFillTile; surfaceShaderSetOptions.colorToAlpha = applyColorToAlpha; + surfaceShaderSetOptions.showUndergroundColor = showUndergroundColor; var count = surfaceTile.renderedMesh.indices.length; if (!showSkirts) { diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 2485ade22955..09f48cb4fd93 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -84,6 +84,11 @@ uniform vec3 u_hsbShift; // Hue, saturation, brightness uniform vec4 u_fillHighlightColor; #endif +#ifdef UNDERGROUND_COLOR +uniform vec4 u_undergroundColor; +uniform vec4 u_undergroundColorByDistance; +#endif + varying vec3 v_positionMC; varying vec3 v_positionEC; varying vec3 v_textureCoordinates; @@ -96,8 +101,11 @@ varying float v_slope; varying float v_aspect; #endif -#if defined(FOG) || defined(GROUND_ATMOSPHERE) +#if defined(FOG) || defined(GROUND_ATMOSPHERE) || defined(UNDERGROUND_COLOR) varying float v_distance; +#endif + +#if defined(FOG) || defined(GROUND_ATMOSPHERE) varying vec3 v_fogRayleighColor; varying vec3 v_fogMieColor; #endif @@ -107,6 +115,25 @@ varying vec3 v_rayleighColor; varying vec3 v_mieColor; #endif +#ifdef UNDERGROUND_COLOR +float interpolateByDistance(vec4 nearFarScalar) +{ + float startDistance = nearFarScalar.x; + float startValue = nearFarScalar.y; + float endDistance = nearFarScalar.z; + float endValue = nearFarScalar.w; + float t = clamp((v_distance - startDistance) / (endDistance - startDistance), 0.0, 1.0); + return mix(startValue, endValue, t); +} +#endif + +#ifdef(UNDERGROUND_COLOR) +vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor) +{ + return sourceColor * vec4(sourceColor.aaa, 1.0) + destinationColor * (1.0 - sourceColor.a); +} +#endif + vec4 sampleAndBlend( vec4 previousColor, sampler2D textureToSample, @@ -425,6 +452,16 @@ void main() finalColor = vec4(mix(finalColor.rgb, groundAtmosphereColor, fade), finalColor.a); #endif +#ifdef UNDERGROUND_COLOR + // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. + if (gl_FrontFacing == false) + { + float blendAmount = interpolateByDistance(u_undergroundColorByDistance); + vec4 undergroundColor = vec4(u_undergroundColor.rgb, u_undergroundColor.a * blendAmount); + finalColor = alphaBlend(undergroundColor, finalColor); + } +#endif + gl_FragColor = finalColor; } diff --git a/Source/Shaders/GlobeVS.glsl b/Source/Shaders/GlobeVS.glsl index c0d6aa757d5d..66e8347fc366 100644 --- a/Source/Shaders/GlobeVS.glsl +++ b/Source/Shaders/GlobeVS.glsl @@ -28,8 +28,11 @@ varying float v_aspect; varying float v_height; #endif -#if defined(FOG) || defined(GROUND_ATMOSPHERE) +#if defined(FOG) || defined(GROUND_ATMOSPHERE) || defined(UNDERGROUND_COLOR) varying float v_distance; +#endif + +#if defined(FOG) || defined(GROUND_ATMOSPHERE) varying vec3 v_fogMieColor; varying vec3 v_fogRayleighColor; #endif @@ -172,6 +175,9 @@ void main() AtmosphereColor atmosFogColor = computeGroundAtmosphereFromSpace(position3DWC, false, vec3(0.0)); v_fogMieColor = atmosFogColor.mie; v_fogRayleighColor = atmosFogColor.rayleigh; +#endif + +#if defined(FOG) || defined(GROUND_ATMOSPHERE) || defined(UNDERGROUND_COLOR) v_distance = length((czm_modelView3D * vec4(position3DWC, 1.0)).xyz); #endif diff --git a/Specs/Scene/GlobeSpec.js b/Specs/Scene/GlobeSpec.js index fae9596de8a0..2e2f14284048 100644 --- a/Specs/Scene/GlobeSpec.js +++ b/Specs/Scene/GlobeSpec.js @@ -3,6 +3,10 @@ import { Rectangle } from "../../Source/Cesium.js"; import { Resource } from "../../Source/Cesium.js"; import { Globe } from "../../Source/Cesium.js"; import { SingleTileImageryProvider } from "../../Source/Cesium.js"; +import { Color } from "../../Source/Cesium.js"; +import { Cartesian3 } from "../../Source/Cesium.js"; +import { HeadingPitchRoll } from "../../Source/Cesium.js"; +import { NearFarScalar } from "../../Source/Cesium.js"; import createScene from "../createScene.js"; import pollToPromise from "../pollToPromise.js"; @@ -412,6 +416,59 @@ describe( ); }); }); + + it("sets underground color", function () { + globe.undergroundColor = Color.RED; + + scene.camera.setView({ + destination: new Cartesian3( + -524251.65918537375, + -5316355.5357514685, + 3400179.253223899 + ), + orientation: new HeadingPitchRoll( + 0.22779127099032603, + -0.7030060668670961, + 0.0024147223687949193 + ), + }); + + return updateUntilDone(globe).then(function () { + expect(scene).toRender([255, 0, 0, 255]); + }); + }); + + it("sets underground color by distance", function () { + globe.baseColor = Color.BLACK; + globe.undergroundColor = Color.RED; + var radius = globe.ellipsoid.maximumRadius; + globe.undergroundColorByDistance = new NearFarScalar( + radius * 0.25, + 0.0, + radius * 2.0, + 1.0 + ); + + scene.camera.setView({ + destination: new Cartesian3( + -524251.65918537375, + -5316355.5357514685, + 3400179.253223899 + ), + orientation: new HeadingPitchRoll( + 0.24245689061958142, + -0.445653254172905, + 0.0024147223687949193 + ), + }); + + return updateUntilDone(globe).then(function () { + expect(scene).toRenderAndCall(function (rgba) { + expect(rgba[0]).toBeGreaterThan(0); + expect(rgba[0]).toBeLessThan(255); + }); + }); + }); }, "WebGL" ); From 1029ec9e6d89f95e46410027665af58684bde122 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Sun, 17 May 2020 20:54:50 -0400 Subject: [PATCH 02/13] Add getters/setters, Sandcastle, tests --- .../models/ParcLeadMine/ParcLeadMine.glb | Bin 0 -> 63056 bytes .../Sandcastle/gallery/Underground Color.html | 230 ++++++++++++++++++ Apps/Sandcastle/gallery/Underground Color.jpg | Bin 0 -> 18640 bytes LICENSE.md | 6 + Source/Scene/Globe.js | 87 ++++--- Source/Shaders/GlobeFS.glsl | 2 +- Specs/Scene/GlobeSpec.js | 19 ++ 7 files changed, 314 insertions(+), 30 deletions(-) create mode 100644 Apps/SampleData/models/ParcLeadMine/ParcLeadMine.glb create mode 100644 Apps/Sandcastle/gallery/Underground Color.html create mode 100644 Apps/Sandcastle/gallery/Underground Color.jpg diff --git a/Apps/SampleData/models/ParcLeadMine/ParcLeadMine.glb b/Apps/SampleData/models/ParcLeadMine/ParcLeadMine.glb new file mode 100644 index 0000000000000000000000000000000000000000..039106ffce3c4315a3694306a1841278425d73bf GIT binary patch literal 63056 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 literal 0 HcmV?d00001 diff --git a/Apps/Sandcastle/gallery/Underground Color.html b/Apps/Sandcastle/gallery/Underground Color.html new file mode 100644 index 000000000000..2d2450177e07 --- /dev/null +++ b/Apps/Sandcastle/gallery/Underground Color.html @@ -0,0 +1,230 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + + + + + + + + + + + + + + + + + + + + + +
Enabled + +
Near distance + + +
Far distance + + +
Near alpha + + +
Far alpha + + +
+
+ + + diff --git a/Apps/Sandcastle/gallery/Underground Color.jpg b/Apps/Sandcastle/gallery/Underground Color.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77bb505db6b25186edfa5c090c6161e167341bc5 GIT binary patch literal 18640 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
- * To disable underground coloring, set undergroundColor to undefined. - * - * @type {Color} - * @default {@link Color.BLACK} - * - * @see Globe#undergroundColorByDistance - */ - this.undergroundColor = Color.clone(Color.BLACK); - - /** - * Gets or sets the near and far distance for blending {@link Globe#undergroundColor} with the globe color. - * The blending amount will interpolate between the {@link NearFarScalar#nearValue} and - * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds - * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. - * Outside of these ranges the blending amount remains clamped to the nearest bound. If undefined, - * the underground color will not be blended with the globe color. - * - * @type {NearFarScalar} - * - * @see Globe#undergroundColor - * - */ - this.undergroundColorByDistance = new NearFarScalar( + this._undergroundColor = Color.clone(Color.BLACK); + this._undergroundColorByDistance = new NearFarScalar( ellipsoid.maximumRadius / 1000.0, 0.0, ellipsoid.maximumRadius / 5.0, @@ -504,6 +479,60 @@ Object.defineProperties(Globe.prototype, { } }, }, + + /** + * The color to render the back side of the globe when the camera is underground or the globe is translucent, + * blended with the globe color based on the camera's distance. + *

+ * To disable underground coloring, set undergroundColor to undefined. + * + * @memberof Globe.prototype + * @type {Color} + * @default {@link Color.BLACK} + * + * @see Globe#undergroundColorByDistance + */ + undergroundColor: { + get: function () { + return this._undergroundColor; + }, + set: function (value) { + this._undergroundColor = Color.clone(value, this._undergroundColor); + }, + }, + + /** + * Gets or sets the near and far distance for blending {@link Globe#undergroundColor} with the globe color. + * The blending amount will interpolate between the {@link NearFarScalar#nearValue} and + * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds + * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. + * Outside of these ranges the blending amount remains clamped to the nearest bound. If undefined, + * the underground color will not be blended with the globe color. + * + * @memberof Globe.prototype + * @type {NearFarScalar} + * + * @see Globe#undergroundColor + * + */ + undergroundColorByDistance: { + get: function () { + return this._undergroundColorByDistance; + }, + set: function (value) { + //>>includeStart('debug', pragmas.debug); + if (defined(value) && value.far < value.near) { + throw new DeveloperError( + "far distance must be greater than near distance." + ); + } + //>>includeEnd('debug'); + this._undergroundColorByDistance = NearFarScalar.clone( + value, + this._undergroundColorByDistance + ); + }, + }, }); function makeShadersDirty(globe) { @@ -903,8 +932,8 @@ Globe.prototype.beginFrame = function (frameState) { tileProvider.fillHighlightColor = this.fillHighlightColor; tileProvider.showSkirts = this.showSkirts; tileProvider.backFaceCulling = this.backFaceCulling; - tileProvider.undergroundColor = this.undergroundColor; - tileProvider.undergroundColorByDistance = this.undergroundColorByDistance; + tileProvider.undergroundColor = this._undergroundColor; + tileProvider.undergroundColorByDistance = this._undergroundColorByDistance; surface.beginFrame(frameState); } }; diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 09f48cb4fd93..cb8d306b4d55 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -127,7 +127,7 @@ float interpolateByDistance(vec4 nearFarScalar) } #endif -#ifdef(UNDERGROUND_COLOR) +#ifdef UNDERGROUND_COLOR vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor) { return sourceColor * vec4(sourceColor.aaa, 1.0) + destinationColor * (1.0 - sourceColor.a); diff --git a/Specs/Scene/GlobeSpec.js b/Specs/Scene/GlobeSpec.js index 2e2f14284048..dd572cec186d 100644 --- a/Specs/Scene/GlobeSpec.js +++ b/Specs/Scene/GlobeSpec.js @@ -417,6 +417,10 @@ describe( }); }); + it("gets underground color", function () { + expect(globe.undergroundColor).toEqual(Color.BLACK); + }); + it("sets underground color", function () { globe.undergroundColor = Color.RED; @@ -438,6 +442,10 @@ describe( }); }); + it("gets underground color by distance", function () { + expect(globe.undergroundColorByDistance).toBeDefined(); + }); + it("sets underground color by distance", function () { globe.baseColor = Color.BLACK; globe.undergroundColor = Color.RED; @@ -469,6 +477,17 @@ describe( }); }); }); + + it("throws if underground color by distance far is less than near", function () { + expect(function () { + globe.undergroundColorByDistance = new NearFarScalar( + 1.0, + 0.0, + 0.0, + 1.0 + ); + }).toThrowDeveloperError(); + }); }, "WebGL" ); From dcc548f58b69dd9d5d344eca1da932b6f3165054 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Sun, 17 May 2020 21:03:59 -0400 Subject: [PATCH 03/13] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 399b835c13ee..f7fa42bcef11 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,7 +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 `Globe.undergroundColor` and `Globe.undergroundColorByDistance` for controlling how the back side of the globe is rendered when the camera is underground or the globe is translucent. +- Added `Globe.undergroundColor` and `Globe.undergroundColorByDistance` 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: From 92465c318e29f1bbc749a7b93f11e09378bcab59 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 19 May 2020 22:01:29 -0400 Subject: [PATCH 04/13] Distance relative to globe surface --- Source/Renderer/AutomaticUniforms.js | 14 ++++++++++++++ Source/Renderer/UniformState.js | 14 ++++++++++++++ Source/Shaders/GlobeFS.glsl | 8 +++++--- Specs/Renderer/AutomaticUniformSpec.js | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Source/Renderer/AutomaticUniforms.js b/Source/Renderer/AutomaticUniforms.js index b4de4b7c7d94..6ed3a9dda20a 100644 --- a/Source/Renderer/AutomaticUniforms.js +++ b/Source/Renderer/AutomaticUniforms.js @@ -1896,5 +1896,19 @@ var AutomaticUniforms = { return uniformState.ellipsoid.oneOverRadii; }, }), + + /** + * An automatic GLSL uniform that stores the camera's height above the ellipsoid. + * + * @alias czm_cameraHeight + * @glslUniform + */ + czm_cameraHeight: new AutomaticUniform({ + size: 1, + datatype: WebGLConstants.FLOAT, + getValue: function (uniformState) { + return uniformState.cameraHeight; + }, + }), }; export default AutomaticUniforms; diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index d456419789c0..1624b0fdaf0f 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -141,6 +141,7 @@ function UniformState() { this._cameraDirection = new Cartesian3(); this._cameraRight = new Cartesian3(); this._cameraUp = new Cartesian3(); + this._cameraHeight = 0.0; this._frustum2DWidth = 0.0; this._eyeHeight2D = new Cartesian2(); this._pixelRatio = 1.0; @@ -1010,6 +1011,18 @@ Object.defineProperties(UniformState.prototype, { return defaultValue(this._ellipsoid, Ellipsoid.WGS84); }, }, + + /** + * The camera's height above the ellipsoid. + * + * @memberof UniformState.prototype + * @type {Number} + */ + cameraHeight: { + get: function () { + return this._cameraHeight; + }, + }, }); function setView(uniformState, matrix) { @@ -1060,6 +1073,7 @@ function setCamera(uniformState, camera) { Cartesian3.clone(camera.directionWC, uniformState._cameraDirection); Cartesian3.clone(camera.rightWC, uniformState._cameraRight); Cartesian3.clone(camera.upWC, uniformState._cameraUp); + uniformState._cameraHeight = camera.positionCartographic.height; uniformState._encodedCameraPositionMCDirty = true; } diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index cb8d306b4d55..58d0a8a04958 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -116,13 +116,13 @@ varying vec3 v_mieColor; #endif #ifdef UNDERGROUND_COLOR -float interpolateByDistance(vec4 nearFarScalar) +float interpolateByDistance(vec4 nearFarScalar, float distance) { float startDistance = nearFarScalar.x; float startValue = nearFarScalar.y; float endDistance = nearFarScalar.z; float endValue = nearFarScalar.w; - float t = clamp((v_distance - startDistance) / (endDistance - startDistance), 0.0, 1.0); + float t = clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0); return mix(startValue, endValue, t); } #endif @@ -456,7 +456,9 @@ void main() // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. if (gl_FrontFacing == false) { - float blendAmount = interpolateByDistance(u_undergroundColorByDistance); + float distanceFromEllipsoid = max(czm_cameraHeight, 0.0); + float distance = max(v_distance - distanceFromEllipsoid, 0.0); + float blendAmount = interpolateByDistance(u_undergroundColorByDistance, distance); vec4 undergroundColor = vec4(u_undergroundColor.rgb, u_undergroundColor.a * blendAmount); finalColor = alphaBlend(undergroundColor, finalColor); } diff --git a/Specs/Renderer/AutomaticUniformSpec.js b/Specs/Renderer/AutomaticUniformSpec.js index c795dbba7ae3..f655a2b3fef1 100644 --- a/Specs/Renderer/AutomaticUniformSpec.js +++ b/Specs/Renderer/AutomaticUniformSpec.js @@ -1,5 +1,6 @@ import { Cartesian2 } from "../../Source/Cesium.js"; import { Cartesian3 } from "../../Source/Cesium.js"; +import { Cartographic } from "../../Source/Cesium.js"; import { Color } from "../../Source/Cesium.js"; import { defaultValue } from "../../Source/Cesium.js"; import { DirectionalLight } from "../../Source/Cesium.js"; @@ -73,6 +74,7 @@ describe( ), rightWC: defaultValue(right, Cartesian3.clone(Cartesian3.UNIT_X)), upWC: defaultValue(up, Cartesian3.clone(Cartesian3.UNIT_Y)), + positionCartographic: new Cartographic(0.0, 0.0, 10.0), }; } @@ -2169,6 +2171,20 @@ describe( fragmentShader: fs, }).contextToRender(); }); + + it("has czm_cameraHeight", function () { + var frameState = createFrameState(context, createMockCamera()); + context.uniformState.update(frameState); + + var fs = + "void main() { " + + " gl_FragColor = vec4(czm_cameraHeight == 10.0); " + + "}"; + expect({ + context: context, + fragmentShader: fs, + }).contextToRender(); + }); }, "WebGL" ); From 3ac1bdffb0be39e6536d724c8e056fdffc0b8939 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 19 May 2020 22:18:03 -0400 Subject: [PATCH 05/13] Rename undergroundColorByDistance to undergroundColorAlphaByDistance --- .../Sandcastle/gallery/Underground Color.html | 8 ++--- CHANGES.md | 2 +- Source/Renderer/UniformState.js | 9 +++++- Source/Scene/Globe.js | 21 +++++++------ Source/Scene/GlobeSurfaceTileProvider.js | 30 +++++++++---------- Source/Shaders/GlobeFS.glsl | 4 +-- Specs/Scene/GlobeSpec.js | 6 ++-- 7 files changed, 45 insertions(+), 35 deletions(-) diff --git a/Apps/Sandcastle/gallery/Underground Color.html b/Apps/Sandcastle/gallery/Underground Color.html index 2d2450177e07..87fa76e5bcf6 100644 --- a/Apps/Sandcastle/gallery/Underground Color.html +++ b/Apps/Sandcastle/gallery/Underground Color.html @@ -213,10 +213,10 @@ var farAlpha = Number(viewModel.farAlpha); farAlpha = isNaN(farAlpha) ? 1.0 : farAlpha; - globe.undergroundColorByDistance.near = nearDistance; - globe.undergroundColorByDistance.far = farDistance; - globe.undergroundColorByDistance.nearValue = nearAlpha; - globe.undergroundColorByDistance.farValue = farAlpha; + globe.undergroundColorAlphaByDistance.near = nearDistance; + globe.undergroundColorAlphaByDistance.far = farDistance; + globe.undergroundColorAlphaByDistance.nearValue = nearAlpha; + globe.undergroundColorAlphaByDistance.farValue = farAlpha; } update(); //Sandcastle_End Sandcastle.finishedLoading(); diff --git a/CHANGES.md b/CHANGES.md index f7fa42bcef11..be5e8d040ad9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,7 +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 `Globe.undergroundColor` and `Globe.undergroundColorByDistance` 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) +- 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: diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 1624b0fdaf0f..4b5537650cf5 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -1073,7 +1073,14 @@ function setCamera(uniformState, camera) { Cartesian3.clone(camera.directionWC, uniformState._cameraDirection); Cartesian3.clone(camera.rightWC, uniformState._cameraRight); Cartesian3.clone(camera.upWC, uniformState._cameraUp); - uniformState._cameraHeight = camera.positionCartographic.height; + + var positionCartographic = camera.positionCartographic; + if (!defined(positionCartographic)) { + uniformState._cameraHeight = -uniformState._ellipsoid.maximumComponent; + } else { + uniformState._cameraHeight = positionCartographic.height; + } + uniformState._encodedCameraPositionMCDirty = true; } diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js index 2e894b5ddfae..1bbdbdf96deb 100644 --- a/Source/Scene/Globe.js +++ b/Source/Scene/Globe.js @@ -63,7 +63,7 @@ function Globe(ellipsoid) { this._terrainProviderChanged = new Event(); this._undergroundColor = Color.clone(Color.BLACK); - this._undergroundColorByDistance = new NearFarScalar( + this._undergroundColorAlphaByDistance = new NearFarScalar( ellipsoid.maximumRadius / 1000.0, 0.0, ellipsoid.maximumRadius / 5.0, @@ -490,7 +490,7 @@ Object.defineProperties(Globe.prototype, { * @type {Color} * @default {@link Color.BLACK} * - * @see Globe#undergroundColorByDistance + * @see Globe#undergroundColorAlphaByDistance */ undergroundColor: { get: function () { @@ -503,11 +503,14 @@ Object.defineProperties(Globe.prototype, { /** * Gets or sets the near and far distance for blending {@link Globe#undergroundColor} with the globe color. - * The blending amount will interpolate between the {@link NearFarScalar#nearValue} and + * The alpha will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. - * Outside of these ranges the blending amount remains clamped to the nearest bound. If undefined, + * Outside of these ranges the alpha remains clamped to the nearest bound. If undefined, * the underground color will not be blended with the globe color. + *

+ * When the camera is above the ellipsoid the distance is computed from the nearest + * point on the ellipsoid instead of the camera's position. * * @memberof Globe.prototype * @type {NearFarScalar} @@ -515,9 +518,9 @@ Object.defineProperties(Globe.prototype, { * @see Globe#undergroundColor * */ - undergroundColorByDistance: { + undergroundColorAlphaByDistance: { get: function () { - return this._undergroundColorByDistance; + return this._undergroundColorAlphaByDistance; }, set: function (value) { //>>includeStart('debug', pragmas.debug); @@ -527,9 +530,9 @@ Object.defineProperties(Globe.prototype, { ); } //>>includeEnd('debug'); - this._undergroundColorByDistance = NearFarScalar.clone( + this._undergroundColorAlphaByDistance = NearFarScalar.clone( value, - this._undergroundColorByDistance + this._undergroundColorAlphaByDistance ); }, }, @@ -933,7 +936,7 @@ Globe.prototype.beginFrame = function (frameState) { tileProvider.showSkirts = this.showSkirts; tileProvider.backFaceCulling = this.backFaceCulling; tileProvider.undergroundColor = this._undergroundColor; - tileProvider.undergroundColorByDistance = this._undergroundColorByDistance; + tileProvider.undergroundColorAlphaByDistance = this._undergroundColorAlphaByDistance; surface.beginFrame(frameState); } }; diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 231fbc36fe4f..2a0d91480c11 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -106,7 +106,7 @@ function GlobeSurfaceTileProvider(options) { this.showSkirts = true; this.backFaceCulling = true; this.undergroundColor = undefined; - this.undergroundColorByDistance = undefined; + this.undergroundColorAlphaByDistance = undefined; this._quadtree = undefined; this._terrainProvider = options.terrainProvider; @@ -1590,8 +1590,8 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) { u_undergroundColor: function () { return this.properties.undergroundColor; }, - u_undergroundColorByDistance: function () { - return this.properties.undergroundColorByDistance; + u_undergroundColorAlphaByDistance: function () { + return this.properties.undergroundColorAlphaByDistance; }, // make a separate object so that changes to the properties are seen on @@ -1639,7 +1639,7 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) { localizedCartographicLimitRectangle: new Cartesian4(), undergroundColor: Color.clone(Color.TRANSPARENT), - undergroundColorByDistance: new Cartesian4(), + undergroundColorAlphaByDistance: new Cartesian4(), }, }; @@ -1833,7 +1833,7 @@ var surfaceShaderSetOptionsScratch = { colorToAlpha: undefined, }; -var defaultUndergroundColorByDistance = new NearFarScalar(); +var defaultundergroundColorAlphaByDistance = new NearFarScalar(); function addDrawCommandsForTile(tileProvider, tile, frameState) { var surfaceTile = tile.data; @@ -1878,16 +1878,16 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { tileProvider.undergroundColor, Color.TRANSPARENT ); - var undergroundColorByDistance = defaultValue( - tileProvider.undergroundColorByDistance, - defaultUndergroundColorByDistance + var undergroundColorAlphaByDistance = defaultValue( + tileProvider.undergroundColorAlphaByDistance, + defaultundergroundColorAlphaByDistance ); var showUndergroundColor = cameraUnderground && frameState.mode === SceneMode.SCENE3D && undergroundColor.alpha > 0.0 && - (undergroundColorByDistance.nearValue > 0.0 || - undergroundColorByDistance.farValue > 0.0); + (undergroundColorAlphaByDistance.nearValue > 0.0 || + undergroundColorAlphaByDistance.farValue > 0.0); var showReflectiveOcean = tileProvider.hasWaterMask && defined(waterMaskTexture); @@ -2117,11 +2117,11 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { tileProvider.zoomedOutOceanSpecularIntensity; Cartesian4.fromElements( - undergroundColorByDistance.near, - undergroundColorByDistance.nearValue, - undergroundColorByDistance.far, - undergroundColorByDistance.farValue, - uniformMapProperties.undergroundColorByDistance + undergroundColorAlphaByDistance.near, + undergroundColorAlphaByDistance.nearValue, + undergroundColorAlphaByDistance.far, + undergroundColorAlphaByDistance.farValue, + uniformMapProperties.undergroundColorAlphaByDistance ); Color.clone(undergroundColor, uniformMapProperties.undergroundColor); diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 58d0a8a04958..2bcee67763f4 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -86,7 +86,7 @@ uniform vec4 u_fillHighlightColor; #ifdef UNDERGROUND_COLOR uniform vec4 u_undergroundColor; -uniform vec4 u_undergroundColorByDistance; +uniform vec4 u_undergroundColorAlphaByDistance; #endif varying vec3 v_positionMC; @@ -458,7 +458,7 @@ void main() { float distanceFromEllipsoid = max(czm_cameraHeight, 0.0); float distance = max(v_distance - distanceFromEllipsoid, 0.0); - float blendAmount = interpolateByDistance(u_undergroundColorByDistance, distance); + float blendAmount = interpolateByDistance(u_undergroundColorAlphaByDistance, distance); vec4 undergroundColor = vec4(u_undergroundColor.rgb, u_undergroundColor.a * blendAmount); finalColor = alphaBlend(undergroundColor, finalColor); } diff --git a/Specs/Scene/GlobeSpec.js b/Specs/Scene/GlobeSpec.js index dd572cec186d..c0088821a015 100644 --- a/Specs/Scene/GlobeSpec.js +++ b/Specs/Scene/GlobeSpec.js @@ -443,14 +443,14 @@ describe( }); it("gets underground color by distance", function () { - expect(globe.undergroundColorByDistance).toBeDefined(); + expect(globe.undergroundColorAlphaByDistance).toBeDefined(); }); it("sets underground color by distance", function () { globe.baseColor = Color.BLACK; globe.undergroundColor = Color.RED; var radius = globe.ellipsoid.maximumRadius; - globe.undergroundColorByDistance = new NearFarScalar( + globe.undergroundColorAlphaByDistance = new NearFarScalar( radius * 0.25, 0.0, radius * 2.0, @@ -480,7 +480,7 @@ describe( it("throws if underground color by distance far is less than near", function () { expect(function () { - globe.undergroundColorByDistance = new NearFarScalar( + globe.undergroundColorAlphaByDistance = new NearFarScalar( 1.0, 0.0, 0.0, From 02792c5a742bd8f2828c08a6ea7b09d25ba32107 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 19 May 2020 22:31:21 -0400 Subject: [PATCH 06/13] Updates from review --- Apps/Sandcastle/gallery/Underground Color.html | 4 ++-- Source/Scene/GlobeSurfaceTileProvider.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Apps/Sandcastle/gallery/Underground Color.html b/Apps/Sandcastle/gallery/Underground Color.html index 87fa76e5bcf6..ad05cf450577 100644 --- a/Apps/Sandcastle/gallery/Underground Color.html +++ b/Apps/Sandcastle/gallery/Underground Color.html @@ -85,7 +85,7 @@ type="range" min="0.0" max="1.0" - step="0.1" + step="0.01" data-bind="value: nearAlpha, valueUpdate: 'input'" /> @@ -98,7 +98,7 @@ type="range" min="0.0" max="1.0" - step="0.1" + step="0.01" data-bind="value: farAlpha, valueUpdate: 'input'" /> diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 2a0d91480c11..96695e68b531 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -1833,6 +1833,7 @@ var surfaceShaderSetOptionsScratch = { colorToAlpha: undefined, }; +var defaultUndergroundColor = Color.TRANSPARENT; var defaultundergroundColorAlphaByDistance = new NearFarScalar(); function addDrawCommandsForTile(tileProvider, tile, frameState) { @@ -1876,7 +1877,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { var undergroundColor = defaultValue( tileProvider.undergroundColor, - Color.TRANSPARENT + defaultUndergroundColor ); var undergroundColorAlphaByDistance = defaultValue( tileProvider.undergroundColorAlphaByDistance, From 4e476abcb43943cdfdb71f6b364847c06aa2da6b Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 19 May 2020 22:33:32 -0400 Subject: [PATCH 07/13] Doc [skip ci] --- Source/Renderer/AutomaticUniforms.js | 2 +- Source/Renderer/UniformState.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Renderer/AutomaticUniforms.js b/Source/Renderer/AutomaticUniforms.js index 6ed3a9dda20a..2146ca77b96d 100644 --- a/Source/Renderer/AutomaticUniforms.js +++ b/Source/Renderer/AutomaticUniforms.js @@ -1898,7 +1898,7 @@ var AutomaticUniforms = { }), /** - * An automatic GLSL uniform that stores the camera's height above the ellipsoid. + * An automatic GLSL uniform that stores the camera's height above or below the ellipsoid. * * @alias czm_cameraHeight * @glslUniform diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 4b5537650cf5..5a6c38217f54 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -1013,7 +1013,7 @@ Object.defineProperties(UniformState.prototype, { }, /** - * The camera's height above the ellipsoid. + * The camera's height above or below the ellipsoid. * * @memberof UniformState.prototype * @type {Number} From c73929d5b3113e4879b08c735f5564bd221c5742 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 19 May 2020 23:32:32 -0400 Subject: [PATCH 08/13] Render underground when clipping planes or cartographic limit are being used --- Source/Scene/GlobeSurfaceTileProvider.js | 34 +++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 96695e68b531..edc73c597d67 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -602,6 +602,32 @@ function clipRectangleAntimeridian(tileRectangle, cartographicLimitRectangle) { return splitRectangle; } +function isUndergroundVisible(tileProvider, frameState) { + if (frameState.cameraUnderground) { + return true; + } + + if (tileProvider.backFaceCulling) { + return false; + } + + var clippingPlanes = tileProvider._clippingPlanes; + if (defined(clippingPlanes) && clippingPlanes.enabled) { + return true; + } + + if ( + !Rectangle.equals( + tileProvider.cartographicLimitRectangle, + Rectangle.MAX_VALUE + ) + ) { + return true; + } + + return false; +} + /** * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call @@ -621,7 +647,9 @@ GlobeSurfaceTileProvider.prototype.computeTileVisibility = function ( var distance = this.computeDistanceToTile(tile, frameState); tile._distance = distance; - if (frameState.fog.enabled && !frameState.cameraUnderground) { + var undergroundVisible = isUndergroundVisible(this, frameState); + + if (frameState.fog.enabled && !undergroundVisible) { if (CesiumMath.fog(distance, frameState.fog.density) >= 1.0) { // Tile is completely in fog so return that it is not visible. return Visibility.NONE; @@ -716,7 +744,7 @@ GlobeSurfaceTileProvider.prototype.computeTileVisibility = function ( frameState.mode === SceneMode.SCENE3D && !ortho3D && defined(occluders) && - !frameState.cameraUnderground + !undergroundVisible ) { var occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace; if (!defined(occludeePointInScaledSpace)) { @@ -1884,7 +1912,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) { defaultundergroundColorAlphaByDistance ); var showUndergroundColor = - cameraUnderground && + isUndergroundVisible(tileProvider, frameState) && frameState.mode === SceneMode.SCENE3D && undergroundColor.alpha > 0.0 && (undergroundColorAlphaByDistance.nearValue > 0.0 || From 225ed5dc2b6eedf05fa2e850c8a60aab63116ea9 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 19 May 2020 23:34:20 -0400 Subject: [PATCH 09/13] Add czm_backFacing --- Source/Scene/processModelMaterialsCommon.js | 2 +- Source/Scene/processPbrMaterials.js | 2 +- Source/Shaders/Builtin/Functions/backFacing.glsl | 13 +++++++++++++ Source/Shaders/GlobeFS.glsl | 3 +-- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Source/Shaders/Builtin/Functions/backFacing.glsl diff --git a/Source/Scene/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js index a52836c720d4..ac94c8b8aa92 100644 --- a/Source/Scene/processModelMaterialsCommon.js +++ b/Source/Scene/processModelMaterialsCommon.js @@ -643,7 +643,7 @@ function generateTechnique( fragmentShader += " vec3 normal = normalize(v_normal);\n"; if (khrMaterialsCommon.doubleSided) { // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. - fragmentShader += " if (gl_FrontFacing == false)\n"; + fragmentShader += " if (czm_backFacing())\n"; fragmentShader += " {\n"; fragmentShader += " normal = -normal;\n"; fragmentShader += " }\n"; diff --git a/Source/Scene/processPbrMaterials.js b/Source/Scene/processPbrMaterials.js index b40e6ed50e99..a4b5027269a2 100644 --- a/Source/Scene/processPbrMaterials.js +++ b/Source/Scene/processPbrMaterials.js @@ -768,7 +768,7 @@ function generateTechnique( } if (material.doubleSided) { // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. - fragmentShader += " if (gl_FrontFacing == false)\n"; + fragmentShader += " if (czm_backFacing())\n"; fragmentShader += " {\n"; fragmentShader += " n = -n;\n"; fragmentShader += " }\n"; diff --git a/Source/Shaders/Builtin/Functions/backFacing.glsl b/Source/Shaders/Builtin/Functions/backFacing.glsl new file mode 100644 index 000000000000..701244a81546 --- /dev/null +++ b/Source/Shaders/Builtin/Functions/backFacing.glsl @@ -0,0 +1,13 @@ +/** + * Determines if the fragment is back facing + * + * @name czm_backFacing + * @glslFunction + * + * @returns {bool} true if the fragment is back facing; otherwise, false. + */ +bool czm_backFacing() +{ + // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. + return gl_FrontFacing == false; +} diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 2bcee67763f4..b19a94bfd32b 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -453,8 +453,7 @@ void main() #endif #ifdef UNDERGROUND_COLOR - // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. - if (gl_FrontFacing == false) + if (czm_backFacing()) { float distanceFromEllipsoid = max(czm_cameraHeight, 0.0); float distance = max(v_distance - distanceFromEllipsoid, 0.0); From c92e8586a27e39452312d5e304d402af39519414 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 20 May 2020 00:07:14 -0400 Subject: [PATCH 10/13] Only render ground atmosphere for front faces --- Source/Shaders/GlobeFS.glsl | 48 ++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index b19a94bfd32b..6aa19f54107f 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -255,6 +255,12 @@ vec3 colorCorrect(vec3 rgb) { vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates); vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float specularMapValue, float fade); +#ifdef GROUND_ATMOSPHERE +vec3 computeGroundAtmosphereColor(vec3 fogColor, vec4 finalColor, vec3 atmosphereLightDirection, float cameraDist); +#endif + +const float fExposure = 2.0; + void main() { #ifdef TILE_LIMIT_RECTANGLE @@ -376,7 +382,6 @@ void main() #if defined(FOG) || defined(GROUND_ATMOSPHERE) vec3 fogColor = colorCorrect(v_fogMieColor) + finalColor.rgb * colorCorrect(v_fogRayleighColor); #ifndef HDR - const float fExposure = 2.0; fogColor = vec3(1.0) - exp(-fExposure * fogColor); #endif #endif @@ -408,6 +413,30 @@ void main() return; } + if (!czm_backFacing()) + { + vec3 groundAtmosphereColor = computeGroundAtmosphereColor(fogColor, finalColor, atmosphereLightDirection, cameraDist); + finalColor = vec4(mix(finalColor.rgb, groundAtmosphereColor, fade), finalColor.a); + } +#endif + +#ifdef UNDERGROUND_COLOR + if (czm_backFacing()) + { + float distanceFromEllipsoid = max(czm_cameraHeight, 0.0); + float distance = max(v_distance - distanceFromEllipsoid, 0.0); + float blendAmount = interpolateByDistance(u_undergroundColorAlphaByDistance, distance); + vec4 undergroundColor = vec4(u_undergroundColor.rgb, u_undergroundColor.a * blendAmount); + finalColor = alphaBlend(undergroundColor, finalColor); + } +#endif + + gl_FragColor = finalColor; +} + +#ifdef GROUND_ATMOSPHERE +vec3 computeGroundAtmosphereColor(vec3 fogColor, vec4 finalColor, vec3 atmosphereLightDirection, float cameraDist) +{ #if defined(PER_FRAGMENT_GROUND_ATMOSPHERE) && defined(DYNAMIC_ATMOSPHERE_LIGHTING) && (defined(ENABLE_DAYNIGHT_SHADING) || defined(ENABLE_VERTEX_LIGHTING)) float mpp = czm_metersPerPixel(vec4(0.0, 0.0, -czm_currentFrustum.x, 1.0), 1.0); vec2 xy = gl_FragCoord.xy / czm_viewport.zw * 2.0 - vec2(1.0); @@ -449,22 +478,9 @@ void main() groundAtmosphereColor = czm_saturation(groundAtmosphereColor, 1.6); #endif - finalColor = vec4(mix(finalColor.rgb, groundAtmosphereColor, fade), finalColor.a); -#endif - -#ifdef UNDERGROUND_COLOR - if (czm_backFacing()) - { - float distanceFromEllipsoid = max(czm_cameraHeight, 0.0); - float distance = max(v_distance - distanceFromEllipsoid, 0.0); - float blendAmount = interpolateByDistance(u_undergroundColorAlphaByDistance, distance); - vec4 undergroundColor = vec4(u_undergroundColor.rgb, u_undergroundColor.a * blendAmount); - finalColor = alphaBlend(undergroundColor, finalColor); - } -#endif - - gl_FragColor = finalColor; + return groundAtmosphereColor; } +#endif #ifdef SHOW_REFLECTIVE_OCEAN From 2bcdbac6a5a1b53c0f0ecae5eef7082b45468fde Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 20 May 2020 00:07:36 -0400 Subject: [PATCH 11/13] Show back faces in cartogrphic limit rectangle sandcastle --- .../gallery/Cartographic Limit Rectangle.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Apps/Sandcastle/gallery/Cartographic Limit Rectangle.html b/Apps/Sandcastle/gallery/Cartographic Limit Rectangle.html index b3a9850907e8..94183c92104e 100644 --- a/Apps/Sandcastle/gallery/Cartographic Limit Rectangle.html +++ b/Apps/Sandcastle/gallery/Cartographic Limit Rectangle.html @@ -39,6 +39,9 @@ terrainProvider: Cesium.createWorldTerrain(), }); + var scene = viewer.scene; + var globe = scene.globe; + // Tropics of Cancer and Capricorn var coffeeBeltRectangle = Cesium.Rectangle.fromDegrees( -180.0, @@ -47,9 +50,11 @@ 23.43687 ); - viewer.scene.globe.cartographicLimitRectangle = coffeeBeltRectangle; - viewer.scene.globe.showSkirts = false; - viewer.scene.skyAtmosphere.show = false; + globe.cartographicLimitRectangle = coffeeBeltRectangle; + globe.showSkirts = false; + globe.backFaceCulling = false; + globe.undergroundColor = undefined; + scene.skyAtmosphere.show = false; // Add rectangles to show bounds var rectangles = []; From d6da21ae31faa1510094894986b9ce1c2c271e04 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 20 May 2020 00:11:00 -0400 Subject: [PATCH 12/13] Fix camera height uniform --- Source/Renderer/UniformState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 5a6c38217f54..4f48dddc1539 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -1076,7 +1076,7 @@ function setCamera(uniformState, camera) { var positionCartographic = camera.positionCartographic; if (!defined(positionCartographic)) { - uniformState._cameraHeight = -uniformState._ellipsoid.maximumComponent; + uniformState._cameraHeight = -uniformState._ellipsoid.maximumRadius; } else { uniformState._cameraHeight = positionCartographic.height; } From f57b6ad50bd2a05576b23a946b7ac315a54ae018 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Thu, 21 May 2020 14:25:30 -0400 Subject: [PATCH 13/13] Updates from review --- .../gallery/Cartographic Limit Rectangle.jpg | Bin 17738 -> 16753 bytes Source/Renderer/AutomaticUniforms.js | 35 ++++++++++-------- Source/Renderer/UniformState.js | 35 +++++++++--------- Source/Scene/processModelMaterialsCommon.js | 1 - Source/Scene/processPbrMaterials.js | 1 - Source/Shaders/GlobeFS.glsl | 2 +- Specs/Renderer/AutomaticUniformSpec.js | 28 +++++++------- 7 files changed, 52 insertions(+), 50 deletions(-) diff --git a/Apps/Sandcastle/gallery/Cartographic Limit Rectangle.jpg b/Apps/Sandcastle/gallery/Cartographic Limit Rectangle.jpg index db87f75e3b4c91f1a2da4c871842a8bdab32a9ee..71c823c9144e6adedf1bfccc3df6124d67916b2b 100644 GIT binary patch literal 16753 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 L;7BF>vHAZ1huU$2 literal 17738 zcmeHtbyytBwr>v%F!-Rs8Qk4{aMu7K0TSF@g1fs12p&8kc#z-{T!RG&4gn%)La>lG zWM}7`d++()ci-P{*GzX;)skNItLo}itNQ1=pX&frML}5s0D(Y&65;Mc<1xx`az#4Jb z{<;DH#Ycn`4T0KnY5Jlx61zq}Aa06@n| z2LH*!Qd55Ak@IEy!F1Tx#RRjpkYKtepw6xCB5P@5tK{ou zdDmA%*WB0MT*QJ&N)kidTh!ap#nIBk6z1*d;N&jqEy46lxhNukTg}CUU~;pt64jAY z_|1YSNihAk#mmc!(~FPO+0B}ZM?^$~i<_5=mzM*9;Nm^FOLwJl!0ADY7uLJ+)&dwz+`?Sc+|AO|!`bb& z_?N!Bmae}Ff0Z0;CI3C(=pesQkVrt+keNh(q$$;p5;I=HM04{oCQ=ut3E55J(Gh!_0g(kN=xf|6Bflu>KDvatIwBw!W4Y{|hbu;{BuMuBX{uOY{F?4Zra3oBs#e ze~|l^(*Gd%FXA6b1qV}i8!cP!zmfa9{0BY6l=Rzxze#_y{?Q@p?BMKn7cpm9O6ob8 zn>yH^j95XIzvosTz{rNMB&c_YUzZSHQjEf$Dhl9 zEP#xJbo)mnFyfB_K|uk7Q83WZP$5_tSXh`Cn3&i&_)u&dJRD3+C@~a|fRKoY2n+WP z2{9oFJ|Pj|tr8G2LI#Y2j)HeL&`2U=K_5yei;0dsS48jAD@Ic6Tpr8E!1ppu{ zLqyyEBoGpSun`pvf}oNj;_$cW4-pX^M?z44E&*7`AOH!93`NvjT!;mjDu~QC*)}S$ zh>%uW*#XiJ0BkxkX}Q2o+ zrc@T|!{Gd)aU_;8C_oqna}g&S2!#d-q`(dXMC*xaqrrq)vCK%qg(Lt7BGa8B1KP2R z9?=4%Wtg9ZyCUIZ$Uy0!82dC&3_cN9AgZ*$V1aH(Aq0t80iwiTBQ46`YpewZrJF%@ zfW_>wk7REk5ID3EnLQon#H7P;RiT_n>j^1qVtWulzyFstfK;`|dguGrTh_Kb9 zpNy(zK|Dy4Av{xXtg^uV;^FL5v$2m?yzX`rwXaVWJSL<3yyqqhL8u^1pc?u_;j}=) zx*_t8I(rje`e5y~v%b;d#2L1p+sNsIt5Nc5f4;qw@=P5#G&Hk9A&!Gy?Z*2fQ%>}y zm;u2(o_#5iwv)#rMm}y!WtLxFc?NvjT$9c4{|rBt~m!W&)M{J+ENy&;jtv{d3 z_PDWE9}nP}_y2Mz{=;VenTwQR0Y_q-5DGd3X;H~GlEUKPI`>jTXuPwW1I^cNQ1sw~ zru(wDwdMLDW5ud?@h9{9gVO*U9GZ=v@)5^CKj(9YVqX%?Wqad_J;T^NyK&ioNvgWz z4uR^hxyi(@hnY6eU`P=!u{7CBSfOC5gRfif-rGZtYI_dHdSA3SArY-D!eGEZ`{XOY|ISc?~<2an_(J zDTSArXPgL=%?}~yfn}^C$kkIehMhtBz9x6T&4G#e!j9Z$RmKTi(6L$d4;Y=Xt>4CZS#+aWNZjBkeOS`NziJ$Z#%+R3knv_Z?;8+#O#G zfIMqeNbunmi6`<6iw)X+*RFx-md#d7^+E5T^x+3x>y*CtDw-`Belho2GeoUB3OQmF zrH@X_F69IJaT32C<9cy^=@6sOVX+&j%N=@9)&8=R{P9EmC5N`+O3bfi;o=-OFJCQp zcH${&Vg{)EVDfwo2>?U8JXU-jdY<^x?fA&~Vl0<58rZJ`i<;AexJBrh)xYE+uPsTvV-vGc&gIeaW4BY%j4cJ$v(VjlQ73I zXoWUg-zAxlJpJ-!{$=M@zxbYRRyqH`7uGhrrNo`AxO&E;oe5uYmWR)4jV|NqLN-d@@I!L0)Eu-_P}zUIu$YHResTfHvc`TC-Zut zW0;opre9ZL+S%o?6cnj?!cTnz-hbd3f4tFNkG0Ze9`7~!9o{6{Sx}dMFY#Vq@}OkZ zQ~cuO{=;qF=(YU3u@_JB@5~J;+o3w`d`!;T2QPk#T-l{uxj6pZWC&}sA-<}jFMH#K zW1d|$qOUczM^Sqc(_^pn)!^MzF||QRXF&34*$~aLnxK-oL#JSLef!NfY@C+RfUSqK zyTaKYJhM-Q%+h~=P|mwXKFIASjTj7Me<)86l53##cMg^FSaew{ll$y})le`vcc;Go zJ@Q8o)o}Ge%-Y@ZZJ(T@hAM-dK<)an?L|`3%3hJND3-&s2g3`kF=52J1J@SFr*Sic;{~-)~P}JWAkdCAe|!Hjxno4ByTrF-0(3W<8*x=Qf9aOjCw|9 zcMp!uth>A<+2cO*2+=$R&(>--X8W$qmwe7>I_O<|w;`yc}RVjUI+o8+Y_8r5amT%-q@%?)CXSV&k3rmqYM;hZ67LG5Tyd2yo}Z9>_y&rsuY9;qEvMt=_B&}TbkfT-8PD#jieZttx)hp9`8<&$fEYyM4HU-B0|yh(YV%6-$+-M#J<@IKm%-kik}RQV?{_A_=W+S{ za+*h-7c;c=s=A4!(iCyi2S0EQvtN+YK!^@nItE(~8{T^@`li0V>-qftY4?p?mh=mj zx_8p_JCueaX-lN=$XQ6%>Icr zoj4M_MD51FYag8*P95DxD3ra({Ss6@mJa9Q^>Epvj;Bl7vPY zsSU!4vlzVg*2?z@ll<<>V~ekpz(oh*W7}U?=8rkcFXY0`-UfBB*9NYbmpVK;Ad^W< zYY_0km&u40XHj@wpV97uUMY)R|A5!P1nIt6i`b{6bcq z&mA{`dpY5uqqI);$KI#m40rNWtkeLzr7Mu~ngd?aOM&_Mam%c7*i-YNz-m;w8)$cU4;U)jw|q5IySuV9UwymN+*7`1H}p zJb`iITivdK2D+n4w|k3zpthv!PXKSA{=@N!Jg$y}hDU%Bt}OXj>ELTz8;guvk+8a)d~YCX=k;9Gs@uA$!}jF!gq7rq))hCzmi7Mh8K76~f0sX!<{ zkFD7d{ve4(x6gqm}$OygWu^u?Ua*Yu9S2Iqc_CW z^4$;4wSk$LF+HJs7bxCv$~y;Y}CZn(dc68hAZ zMIuXEMc>rj_i#&xw{S{GFH36-Pt|9}^TQeB%CIAFp5?WzY)w{5GGi#Xmv>Fh(~{72 zB}00&i4}<6fR}iU`?Jc0W!UEl3$eDg8sXL`B8R;6T0kTDfUJVCpVY3~k1VIDXJ%s_ zLtc@qs7FDY&SjY(oPC^3QE zC16QcBPC>quri-M&xIyz9~D`fL~c(A`2$9-c%=+SQshjU*Z3p``rM*P(DW;* z^ZAv~5ltQ4f)JvH;?Eu5C*SB+I1PbThRLJ|=Vq5FZSlyOGF&B*G15MfH#EIxH*SBC z0_7Rx<0n+P@33vO_MXModGbMQNp6!j2E8fi#K%VR2NV6qaGv~29lVmMCx^_+ubukW zAD6jobk@)**OwY=w^XR*lTLeGPK>oEFe@*0hy;l$IS#D3D&Q|G==we1ua_hgA|5BL z>*S1)v{`3nN|Ru8Y4NgF$)W2mmlAX-CAv=y5>7P~b}rh}PpE2tTi0tVnRu|EXtMQ4 z-dAddKb@Sd#~Q%2CL0(zTKPO~FT%Fe6{K%goGNv*SQ29Cy~*hHSgWq4%WA*hjPL{zT&brAxYLd)OksEjy(A~@MK-tRBmN*ZHvV7?Fj#ebesVd zM?Yg@PCn(fGLLLEYGE=R75c4+&(_URmi#5Q0j$q(KBVJ56za6f!+iVHgxdmKiJ_B7 ze*C4_Pt{hp^@*yMR{kns_Kc`k{pW41Qj3{(zd~J0TZKz!5C0{9pw%W&6tf8(U47w#RE@exfhBa`A zM2DQUyv6u>lcv6y#DBPwNQicpsZ4yFdf)4`eCc7{+XqFT=WrZ14h~*CpIK6>V6(7W zi9y5up%*w>@@2mMWtb0}1~pFvym9#|*VydsZgt1g=e_HAKB5QnBM$2_yc zH2;YJ-6-82d3oodiV8@5yD5ck zTZde*KxjHRd?yowD&r^MD3!rrRBq=E(cDpakjbi@7Qvz};wjG)E7K{FUQeZhlo9yR z5KjuG)4{xfS6eVzHG5L^6WA#~Dc5l%XH&y-F*j!AD6-`k7SequmK0!W7ti^XAOqzj ztxAl3g%pxBP^4c8j_~8(-H^uV2!O4|6(R(b78s?$Y`WRxorKY^N}yrZR`m4$C* zxd9)zkH29{KeW;rJixS~2}#_&?&q??jxi)pN|hmM%~r+KhXcq~Kt%0{HR?ljJBA?lTfV}xEQShFNW3uP$EZ?AlC{d_agUu*_#(IO04?^2FS5+6N$fP zz!9Qsk)q}?k&O_|Umq~RCg5yRjxo|1GBG?4jX2fd*OV~o2JJ$Vclw4YHu22;*Vbi8 zp-EP5yuNwQaid)6A{Q%|AM0-z_d@!PgyTXg*7<$1ukRl{>(@Xmd67w6Uln2cTlUCo zkcz_qbhv4E_R^bP=i)Ks1w3Ppp{z6h&zi)E+}e#5aDcSpB&=@0kl zr%!1(;4u^nr!xo^(38ZmY(CHunk`+(f?}iS;-FXHY}lZ}FMDsoDe1c8QlT;L3X)?Z zWIHyy>;O*Rq*Y{EgKpY$p6`UxvbtC~HO%BxDW4&jENHl8)87FPmHWWxT@_Hy;myFt zWpoOfHfj+1*tx4<&{%g;p86<154RHgNmfnvlV%lL2;4hT3oQ2&aNlKSdC!wx&#TE@ zJE}p2C0hz`YasSfHEww1hTSQU^vM)uY>vCPg?YRe_u!{fK6!1BiqM}%e^_?JLvII9G}FYf{046 zNMY}DI0uwnI#pvd{N{cPGHxbm!GTym6AbC2DfeM(J5_?yooKau*h7jjN@_xO(6PWz zz+kXE|FD0ck9o$b7R<8Oo&L;F>Jy%$q2U=#2gaEaY1m^pMkh6tpPg2YW-~_&kUr%C zznu!Ir8PT@PmMxBrKrN^q_2Zg^F3jQ(L zD`U}u*$(k2GZl|{5B3dT(85x|tNd~*G*-9eLhGC*i4+kg zU{*W1qt=sQo>Iuc;z+%D_MzYwhOwD#kbD4QOKSsly zW)^H)qSd+Xd>w6xl5WDAHWD7$-zNB>j!jUx=Ad{J^@s${8qHAgL0cCEtQ`(h9w2Gj zK{e@)hd@A!Sg<O7os;V+h~NQlCP3EkT7;CP*@69|W<=k|pTP@7Y0-A#^L?MyCbg)51%fNw6!#ciFX1Ox zDAB4%1CrXo?MOFkBPf{+oQmnTl?syKt_M>d<&mcMkJoAHA1F6!(>{ghmd+dyxZ}y9 z>c00nClw-n@sT@KC008cyEP)zC%e8SxV=NwLl1>#x5ceRL2lWkp{8P2MikvgNQ#Fs zdVBW>_fbjmr9-avM$~(oQan|X!LN~H7P}36St|HR+?C%XH2m`Vc+<8eVpnG&jQPA3Bd;JIYXk+3?u_@)A$UHMJeLcNEI>AkQ5)@Zb z)1(!<>QevGeSg1*ahR}DW9Z(s0__mNkP0$6E6nSWsU2}tW7jSwteOj6HC_D-Mk}m= zBZQkVrSH;@&hM04Rc*&e*qFD>;u%HAk$i2 zpkO+`h{#5D?P0m3xt5i~j4EU}$1K8`8hH&u>2Y@9VF?Y+t#;(_!i>P6_fMMhk?bq3 zx`rtDZlv`KAOb5uoUizOy=3t20|<7ApJY?-EA1loZW4_#={oyTq$~Mc_*I(my$HiZ zHjgLAbXfqNUi|@9&(U7^(8$YmIO{71qzmPcxYox96i|mI+tX(=!B80(j92K!?~zfF zzFF|Ag!P_6YzK&pRtoET=rdlCf!J++By7M z5>`n0KqJfIU67obnVx~NbH5#T;*;GQIRFt?Ub_*(XiuGsn^uy8ofsiUw6s-L4i6Zt zL3CksEmB9Z+iprk$&(@MnTuG);f=F?v}NSTpLMUexxa1nUCBns+K>d9YZu`uTS#~z zQ-lzQ2_x}Bv1N2QAtpZoBiX85Dq0A&rftNtZS=1}>0J&~Kg5KdLhoF!U52sL^TSn@ zL&9tX!D{`|I3PI2jcjy^3`DpGqv`^qpVhV7B^q|!mFvol|DZRym!zM@U-a~*@L01B ziyQC69)xunVPUwFciauDdUHgL|#Qm4wsLA;C(8NN_NcG8|uvJ{bTbzF#CG1%g4~ zP&j?C%nleGj06Wl(ZK{^=}6KrPz-%Axk#D}nu@l!i!?Yq75#nNM?v}UWWWMHfZA`! zq^1W9rGhi-F6o`WPL^hfoJ#ca!zNGwLN&h7zI1WL4}>cN;W_f8feog!a!3%`^oiRY(!`$$rmLL%Y3AdWbqVj8pRZ*=)kMgt|Szxp%X6u#sgvG8|Q=Z^DKZHtUg=tW<9 z8%}3t%_PJxuHi30&=AoA1%-X~jI1OSUb+SXuZhUA$T%bOI2V_h13#_uiw69<*)T6SZ}T& zrO*6)ve`u8Dxcyws(yV_$x{TmKX5SwMdM4GeH7ZzUReV{TL(wwx_qOq97uZp5eDowfE~ZTG^( zbIQ`_jkLhTY@2EkazI&@kW6UaKC~225!+Re9jGT&5h2~*+p~yG-M`j2DMukib+=0#=$|zX6k1=a^+M6h_As7#R+cyT znUFZ-5N;>FAt#_*3*LFz&=nybnnhG%AjQCJdqOU+MP6!2wr+mugj@l8F7((!rS|PT z6+XgOV?0eQxjBYJ)t9X4iG;4b6N-c?tQ1EQSC)KrA~)1Q z9UI!t)$ZeKUEibOMVo8wn<=Ib)Hk>i)mNN9_d$e84s*A2&#cDjG_dwt{Pl9V7K@Kv zA#B}x)cFFzwD6}CzHNi;Q61X!sKqGM0+i=88SCookxNj_X>=&27tR9md8(I32*@dK zqc&x6%hC>KBGE`s(g(u@CWDo~+jTUufdXq7T&=zT4!g_KEtEZCH>|=qLWHz&QBz_a zHl`nN=Qs*uH#U))Y}Mf29%^R%+fS(JAf;6MtU3kJpsr3Aa)q); zM4a<%Gq_&`_39^3Akr*VxDYPLhl}eW>xr9sAll0I3XGD-oaelY_#6ODyW}%BdJxaz zjIq8&mN1Uib9j+3v32E@;H(eE>q9GjIjyURC5;c{*n)SXvn{cLi}<@Xj6 z>r{2Mu#d+5P1N!gtrn6xEMjBpUTDS_zS9pIjDN~ZP=0V?X*l^P@HDu)qo@;O=J7(QJ;Qg?-Tx*Avm6AMk72LTL zX5A{d_hz_?w@?q#t9Ntv2qN;X-xpD!@lAAa=h=;~L={YM5U7r8V4H}0M1eu39p$Q4M5tA58d@enlALTn<+i<_2S<#MFswekt5jhptuL|Y$RZ)*Q+ z6GT|?`D#B{o!oruV_+?MuZwr9O=P4l+5~oC#8!>w+yI+ZEZy7f2n=M|x(>MOeg4 z|K##UXhE2}=mDk}lkZQ!$#MKZ0*$HKJ9xA3lYz-T1!TJByRcl|$*02sP1+UI;#D?X zR{Nl?0VZoz`43q_CU^LQcNg-d$_bQS6sF|N?D<=2Ym%ic1C_|FPlD~72ks0zy%50I zp^4IF)EC5|X-C_;T!7UXj(iGS+zX^ol@og?Fe7qlHPwHnsY%f#%z(``Upt0}qCVNR z3en<_;`GI%CtoFL=g^t$rG4S|$txjS4iR?2gTu)!W?v1&oUy}sjT5kT5$lWH_6ALLzbd zc%+OK6|L{%dV38E$i1kLR7*0-uz2k>h-0)39#SM-d-IZ@k};lQidqTVpmh0ZvQ7=k z=d0^YYa|J^mogLMMlWqxI#A=aF>9pa^EGp$W%M&@NJ4PbnNF|Q*X=xzE-p7vDwr>> zCg9j#qF$`6*1=U=_C7D{%^yv~Dut=ktnzZ2R8ppSvJGR)x|M~=Oju)LF7h_f2}N9mxW$lk&fZ(#Z2ue%t%u3N$Kp zhgCSU$%x?&`MYfP%WbJQF9i5n$iDl5YJ7vD%DCjebYxDEf0hk zcH|s~er{5+b3Ub;Kkx7Tyw?Uoe#xalSUeUBx}(y$cpq!NiM4(D5c<7Vq%jMEdU7Vo zBY#qGcs(9+mCgJO>ZHY*SJg?q%Jv$s^6<=pA2|8;-Mdys@Y`g0ak%t$jsCaY$pJeT zlfL!$(p z65mrl|GEqmYdwuwi?`-<5nF)gmg1J2_5~N6;2<}MQwa~B5vx2>Yt9xKk#44tc>Hv} z^=n@WQcZGK$es2#5cAf1LzqJ~*#Z;dd*{l!UJXYXq5NJcPPE}vgG>rn_Q*2m+s%0J zSC#uwcL&Kn@uN_24fsjszk?AyrV{PB?@#mk@chjL=w$8shWm@{^Xdt-?7hI&H@uFl zox9&p6MXfiO}zVd32|l@#?ESis7#%vj zX<2Q)kMhZ~)ZxtELKcR>(2o0@%&q7Z9yxoyz^*~{w8FcG4{U`y{dNi2iW{8*eLBT0 z@ZS-aocM?zFQ;zHvLdAoBVPM%B9F0HHiPKKUGcfv4ioU~2lSs@4qB&r_s|V$US-1T z?ftf>-jxTBZl1fbP%>`33j7K9>=k;DFR#U?hoV58EhNV>w$=4-q=bVB`8PZZPg5Qf zzM*7f!O*6>tC*K3`DTD!96Oz|Y%cG770Dztw5&M8YDd9@GG4Dtp`2uzw}LvCEzv@= zJMCyvE&9ALc)eKShPU`=jml^DM>pIRBL?HprD%fnT|cBOj_PbtO@OT4lVsND4w3tOdud_<`#!7wY0%$rB3K{eH;A?@NN`8}dKWU|si`#K}S@jK@=LqBv$c~s3Wq)}7L}gE zHc34YD;*;^LlpRvIRsZEYt3-%^Q3 z(Fz8uiP&^p2T7l&l4Wu8i+5g>`T4rQ?=)CTW=kEpzcLhs}wRuhuquo%& z?3M!2#|BVMY#fh6K7u<^E?U*t?fuvMcaH3t-4eW5p0myPds+K*$zhrRHCVJifde=l zaU$I1d}-~GNbA?V7HB#5BFtz&hF*c)3|r z$XV@GRDC(A)e8$1D!OU+H&17FdhOp8hKUAXJiXcqjgMw}xUfsml1~uVoj-i-SO4~% zhd4#^V2%IgSCqOl?oP>1giZXOLVhnMaTM!hz&d+MsKe$i8cGcJf%HP5rs8-k2ieqR z&G8QhYDu2YlhKDKb7x(}x09UQlDyI62a&90pLqM&DLG z=A6QAJ0F##Vv1}x(_>33zTRL-S=T6I*IHa}RV56yj{-Quvz9b2-w*Yif4vybR685m zfa1eK%yBi*Cp(XxiasQ0>dFiF%37jhBhPf=XLAP9Mwgm&v~U=h-WQit{_bOD1CdvL zc`Zf7n~!GERdcb+uYSkA@W%4Tw+9NEwAhx?(7at7G>-WTJb*5|>83x~pvM$bwx zxgNwa3Y5#5`Uc*sw@7-7=TJeng+b+Yveo(C3^RfJ5nq9z7hgxUc?CEyU z>i3+7a5vXayaP>NUHOt{?&6!i{Jv_eILAKB($ML;Ct8Ieb|2xnH4mUp*N`6gn_Xu% zKGTTaXn97@vqZe&n6`RB5&5A}MYi3BBO0%Sq1m|X&CE-Wi6&EY`e#~|7`^0>8Cm)R zqlIaG2sC-0;Xzm!1{-Y-otKfA;9YNwr(=df%_Y}nLE9PF z9cbEz&YiDq+lr8f@*(v*B(}85id57Q`-5b4C@fBKf?r(ZK0*tjV#Op*Lh&Z=DtCd8 zC8GPh3R5p+VyFr`!%*XbH^57A;#@eeB|<3U0zKeX=pKp^TAr-e1Dx&-IAa;^Xqay7 zCxeFv26eufnFk5$`>{9TA z+Nh{!s{3a3^Q$Xz)ofv~ima#m0D)ALv+6vHQ3J%iFqcn`h#kbLeyA{ZvF=NGS)PI*pcsC?z;-FSZq4`Ir{U9sjjD&#qq7 zcX+!_(m)Ba)576c#$%%&{h1jX#LN1EqB0jI2{&P8z{oYQA%zQguz?@(!Tf`jB73*x zRb3!d-KgEbZ1p==z1eKhx5FiXLeEf$n|CnIAns+4X$>-R z9?Jml$Ow2SF=#OqR}*7y3P;yz49`gQiY!NI(#$jA4AT1kwCyL*EpQMqAF@|`;F0y- z6EY3nGQznqu#*F^XFO*M@2efC+Zr92;&L0SN|`q7=v2GhC=mcy;nCtzdG^*BWqq|R z3s6ZtHtxGajj}z9ofA%_Krr@miOKbAflw$ba(9}$3T7v6y%NSiI7k^l4&K5k;j2j5 zQB0D`GPyhtPB-3px&aDn&I)5#0HXQtW@xIymiKnp)=$fx6Q_13857zLKNETN#6JBe z5H-4G5x9qzTbmgUMn>a?%A*R=h@C@PzLZ)Zx1^?o>SoKn?Y)9kKBf9%&ax0p9-i#Y z_7bDFImO50hMFrO-Xuj^Fc}~KR7{kaV5w;#u+>H W&H4qAS(MhyGg`a*j}C%x) and height squared (y) - * of the eye (camera) in the 2D scene in meters. + * in meters of the eye (camera) above the 2D world plane. This uniform is only valid + * when the {@link SceneMode} is SCENE2D. * * @alias czm_eyeHeight2D * @namespace @@ -1896,19 +1915,5 @@ var AutomaticUniforms = { return uniformState.ellipsoid.oneOverRadii; }, }), - - /** - * An automatic GLSL uniform that stores the camera's height above or below the ellipsoid. - * - * @alias czm_cameraHeight - * @glslUniform - */ - czm_cameraHeight: new AutomaticUniform({ - size: 1, - datatype: WebGLConstants.FLOAT, - getValue: function (uniformState) { - return uniformState.cameraHeight; - }, - }), }; export default AutomaticUniforms; diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 4f48dddc1539..2e52beffefcb 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -141,8 +141,8 @@ function UniformState() { this._cameraDirection = new Cartesian3(); this._cameraRight = new Cartesian3(); this._cameraUp = new Cartesian3(); - this._cameraHeight = 0.0; this._frustum2DWidth = 0.0; + this._eyeHeight = 0.0; this._eyeHeight2D = new Cartesian2(); this._pixelRatio = 1.0; this._orthographicIn3D = false; @@ -673,9 +673,20 @@ Object.defineProperties(UniformState.prototype, { }, /** - * The the height (x) and the height squared (y) - * in meters of the camera above the 2D world plane. This uniform is only valid - * when the {@link SceneMode} equal to SCENE2D. + * The height in meters of the eye (camera) above or below the ellipsoid. + * @memberof UniformState.prototype + * @type {Number} + */ + eyeHeight: { + get: function () { + return this._eyeHeight; + }, + }, + + /** + * The height (x) and the height squared (y) + * in meters of the eye (camera) above the 2D world plane. This uniform is only valid + * when the {@link SceneMode} is SCENE2D. * @memberof UniformState.prototype * @type {Cartesian2} */ @@ -1011,18 +1022,6 @@ Object.defineProperties(UniformState.prototype, { return defaultValue(this._ellipsoid, Ellipsoid.WGS84); }, }, - - /** - * The camera's height above or below the ellipsoid. - * - * @memberof UniformState.prototype - * @type {Number} - */ - cameraHeight: { - get: function () { - return this._cameraHeight; - }, - }, }); function setView(uniformState, matrix) { @@ -1076,9 +1075,9 @@ function setCamera(uniformState, camera) { var positionCartographic = camera.positionCartographic; if (!defined(positionCartographic)) { - uniformState._cameraHeight = -uniformState._ellipsoid.maximumRadius; + uniformState._eyeHeight = -uniformState._ellipsoid.maximumRadius; } else { - uniformState._cameraHeight = positionCartographic.height; + uniformState._eyeHeight = positionCartographic.height; } uniformState._encodedCameraPositionMCDirty = true; diff --git a/Source/Scene/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js index ac94c8b8aa92..5ce0bf0f226a 100644 --- a/Source/Scene/processModelMaterialsCommon.js +++ b/Source/Scene/processModelMaterialsCommon.js @@ -642,7 +642,6 @@ function generateTechnique( if (hasNormals) { fragmentShader += " vec3 normal = normalize(v_normal);\n"; if (khrMaterialsCommon.doubleSided) { - // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. fragmentShader += " if (czm_backFacing())\n"; fragmentShader += " {\n"; fragmentShader += " normal = -normal;\n"; diff --git a/Source/Scene/processPbrMaterials.js b/Source/Scene/processPbrMaterials.js index a4b5027269a2..163ee5731a55 100644 --- a/Source/Scene/processPbrMaterials.js +++ b/Source/Scene/processPbrMaterials.js @@ -767,7 +767,6 @@ function generateTechnique( fragmentShader += " vec3 n = ng;\n"; } if (material.doubleSided) { - // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494. fragmentShader += " if (czm_backFacing())\n"; fragmentShader += " {\n"; fragmentShader += " n = -n;\n"; diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 6aa19f54107f..50cec0797269 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -423,7 +423,7 @@ void main() #ifdef UNDERGROUND_COLOR if (czm_backFacing()) { - float distanceFromEllipsoid = max(czm_cameraHeight, 0.0); + float distanceFromEllipsoid = max(czm_eyeHeight, 0.0); float distance = max(v_distance - distanceFromEllipsoid, 0.0); float blendAmount = interpolateByDistance(u_undergroundColorAlphaByDistance, distance); vec4 undergroundColor = vec4(u_undergroundColor.rgb, u_undergroundColor.a * blendAmount); diff --git a/Specs/Renderer/AutomaticUniformSpec.js b/Specs/Renderer/AutomaticUniformSpec.js index f655a2b3fef1..c7cea212aae4 100644 --- a/Specs/Renderer/AutomaticUniformSpec.js +++ b/Specs/Renderer/AutomaticUniformSpec.js @@ -1947,6 +1947,20 @@ describe( }).contextToRender(); }); + it("has czm_eyeHeight", function () { + var frameState = createFrameState(context, createMockCamera()); + context.uniformState.update(frameState); + + var fs = + "void main() { " + + " gl_FragColor = vec4(czm_eyeHeight == 10.0); " + + "}"; + expect({ + context: context, + fragmentShader: fs, + }).contextToRender(); + }); + it("has czm_eyeHeight2D == 0,0 in Scene3D", function () { var fs = "void main() { " + @@ -2171,20 +2185,6 @@ describe( fragmentShader: fs, }).contextToRender(); }); - - it("has czm_cameraHeight", function () { - var frameState = createFrameState(context, createMockCamera()); - context.uniformState.update(frameState); - - var fs = - "void main() { " + - " gl_FragColor = vec4(czm_cameraHeight == 10.0); " + - "}"; - expect({ - context: context, - fragmentShader: fs, - }).contextToRender(); - }); }, "WebGL" );