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..21b5b4974efc 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" );