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

Ground atmosphere/fog hue, saturation and brightness shifts #7157

Merged
merged 7 commits into from
Oct 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions Apps/Sandcastle/gallery/Sky Atmosphere.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
});
var scene = viewer.scene;
var skyAtmosphere = scene.skyAtmosphere;
var globe = scene.globe;

// The viewModel tracks the state of our mini application.
var viewModel = {
Expand All @@ -81,20 +82,21 @@
Cesium.knockout.applyBindings(viewModel, toolbar);

// Make the skyAtmosphere's HSB parameters subscribers of the viewModel.
function subscribeParameter(name) {
function subscribeParameter(name, globeName) {
Cesium.knockout.getObservable(viewModel, name).subscribe(
function(newValue) {
skyAtmosphere[name] = newValue;
globe[globeName] = newValue;
}
);
}

subscribeParameter('hueShift');
subscribeParameter('saturationShift');
subscribeParameter('brightnessShift');
subscribeParameter('hueShift', 'atmosphereHueShift');
subscribeParameter('saturationShift', 'atmosphereSaturationShift');
subscribeParameter('brightnessShift', 'atmosphereBrightnessShift');

Sandcastle.addToggleButton('Lighting', scene.globe.enableLighting, function(checked) {
scene.globe.enableLighting = checked;
Sandcastle.addToggleButton('Lighting', globe.enableLighting, function(checked) {
globe.enableLighting = checked;
});

Sandcastle.addToggleButton('Fog', scene.fog.enabled, function(checked) {
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Change Log
* Added `cutoutRectangle` to `ImageryLayer`, which allows cutting out rectangular areas in imagery layers to reveal underlying imagery. [#7056](https://github.com/AnalyticalGraphicsInc/cesium/pull/7056)
* Added `imageBasedLightingFactor` property to `Cesium3DTileset`, `Model`, and `ModelGraphics` to scale the diffuse and specular image-based lighting contributions to the final color. [#7025](https://github.com/AnalyticalGraphicsInc/cesium/pull/7025)
* Added `lightColor` property to `Cesium3DTileset`, `Model`, and `ModelGraphics` to change the intensity of the light used when shading model. [#7025](https://github.com/AnalyticalGraphicsInc/cesium/pull/7025)
* Added `atmosphereHueShift`, `atmosphereSaturationShift`, and `atmosphereBrightnessShift` properties to `Globe` which shift the color of the ground atmosphere to match the hue, saturation, and brightness shifts of the sky atmosphere. [#4195](https://github.com/AnalyticalGraphicsInc/cesium/issues/4195)

##### Fixes :wrench:
* Fixed an issue where `pickPosition` would return incorrect results when called after `sampleHeight` or `clampToHeight`. [#7113](https://github.com/AnalyticalGraphicsInc/cesium/pull/7113)
Expand Down
27 changes: 27 additions & 0 deletions Source/Scene/Globe.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,30 @@ define([
*/
this.shadows = ShadowMode.RECEIVE_ONLY;

/**
* The hue shift to apply to the atmosphere. Defaults to 0.0 (no shift).
* A hue shift of 1.0 indicates a complete rotation of the hues available.
* @type {Number}
* @default 0.0
*/
this.atmosphereHueShift = 0.0;

/**
* The saturation shift to apply to the atmosphere. Defaults to 0.0 (no shift).
* A saturation shift of -1.0 is monochrome.
* @type {Number}
* @default 0.0
*/
this.atmosphereSaturationShift = 0.0;

/**
* The brightness shift to apply to the atmosphere. Defaults to 0.0 (no shift).
* A brightness shift of -1.0 is complete darkness, which will let space show through.
* @type {Number}
* @default 0.0
*/
this.atmosphereBrightnessShift = 0.0;

this._oceanNormalMap = undefined;
this._zoomedOutOceanSpecularIntensity = undefined;
}
Expand Down Expand Up @@ -688,6 +712,9 @@ define([
tileProvider.enableLighting = this.enableLighting;
tileProvider.showGroundAtmosphere = this.showGroundAtmosphere;
tileProvider.shadows = this.shadows;
tileProvider.hueShift = this.atmosphereHueShift;
tileProvider.saturationShift = this.atmosphereSaturationShift;
tileProvider.brightnessShift = this.atmosphereBrightnessShift;

surface.beginFrame(frameState);
}
Expand Down
8 changes: 7 additions & 1 deletion Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ define([
var clippingPlanes = options.clippingPlanes;
var clippedByBoundaries = options.clippedByBoundaries;
var hasImageryLayerCutout = options.hasImageryLayerCutout;
var colorCorrect = options.colorCorrect;

var quantization = 0;
var quantizationDefine = '';
Expand Down Expand Up @@ -142,7 +143,8 @@ define([
(enableClippingPlanes << 18) |
(vertexLogDepth << 19) |
(cartographicLimitRectangleFlag << 20) |
(imageryCutoutFlag << 21);
(imageryCutoutFlag << 21) |
(colorCorrect << 22);

var currentClippingShaderState = 0;
if (defined(clippingPlanes)) {
Expand Down Expand Up @@ -237,6 +239,10 @@ define([
fs.defines.push('ENABLE_CLIPPING_PLANES');
}

if (colorCorrect) {
fs.defines.push('COLOR_CORRECT');
}

var computeDayColor = '\
vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates)\n\
{\n\
Expand Down
23 changes: 22 additions & 1 deletion Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ define([
this.showGroundAtmosphere = false;
this.shadows = ShadowMode.RECEIVE_ONLY;

this.hueShift = undefined;
this.saturationShift = undefined;
this.brightnessShift = undefined;

this._quadtree = undefined;
this._terrainProvider = options.terrainProvider;
this._imageryLayers = options.imageryLayers;
Expand Down Expand Up @@ -981,6 +985,9 @@ define([
u_minimumBrightness : function() {
return frameState.fog.minimumBrightness;
},
u_hsbShift : function() {
return this.properties.hsbShift;
},

// make a separate object so that changes to the properties are seen on
// derived commands that combine another uniform map with this one.
Expand All @@ -990,6 +997,7 @@ define([
oceanNormalMap : undefined,
lightingFadeDistance : new Cartesian2(6500000.0, 9000000.0),
nightFadeDistance : new Cartesian2(10000000.0, 40000000.0),
hsbShift : new Cartesian3(),

center3D : undefined,
rtc : new Cartesian3(),
Expand Down Expand Up @@ -1166,7 +1174,8 @@ define([
enableClippingPlanes : undefined,
clippingPlanes : undefined,
clippedByBoundaries : undefined,
hasImageryLayerCutout : undefined
hasImageryLayerCutout : undefined,
colorCorrect : undefined
};

function addDrawCommandsForTile(tileProvider, tile, frameState) {
Expand Down Expand Up @@ -1194,6 +1203,14 @@ define([
var castShadows = ShadowMode.castShadows(tileProvider.shadows);
var receiveShadows = ShadowMode.receiveShadows(tileProvider.shadows);

var hueShift = tileProvider.hueShift;
var saturationShift = tileProvider.saturationShift;
var brightnessShift = tileProvider.brightnessShift;

var colorCorrect = !(CesiumMath.equalsEpsilon(hueShift, 0.0, CesiumMath.EPSILON7) &&
CesiumMath.equalsEpsilon(saturationShift, 0.0, CesiumMath.EPSILON7) &&
CesiumMath.equalsEpsilon(brightnessShift, 0.0, CesiumMath.EPSILON7));

var perFragmentGroundAtmosphere = false;
if (showGroundAtmosphere) {
var mode = frameState.mode;
Expand Down Expand Up @@ -1367,6 +1384,8 @@ define([
var localizedCartographicLimitRectangle = localizedCartographicLimitRectangleScratch;
var cartographicLimitRectangle = clipRectangleAntimeridian(tile.rectangle, tileProvider.cartographicLimitRectangle);

Cartesian3.fromElements(hueShift, saturationShift, brightnessShift, uniformMapProperties.hsbShift);

var cartographicTileRectangle = tile.rectangle;
var inverseTileWidth = 1.0 / cartographicTileRectangle.width;
var inverseTileHeight = 1.0 / cartographicTileRectangle.height;
Expand All @@ -1379,6 +1398,7 @@ define([

// For performance, use fog in the shader only when the tile is in fog.
var applyFog = enableFog && CesiumMath.fog(tile._distance, frameState.fog.density) > CesiumMath.EPSILON3;
colorCorrect = colorCorrect && (applyFog || showGroundAtmosphere);

var applyBrightness = false;
var applyContrast = false;
Expand Down Expand Up @@ -1510,6 +1530,7 @@ define([
surfaceShaderSetOptions.enableClippingPlanes = clippingPlanesEnabled;
surfaceShaderSetOptions.clippingPlanes = clippingPlanes;
surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;
surfaceShaderSetOptions.colorCorrect = colorCorrect;

command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(surfaceShaderSetOptions);
command.castShadows = castShadows;
Expand Down
22 changes: 20 additions & 2 deletions Source/Shaders/GlobeFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ uniform vec4 u_clippingPlanesEdgeStyle;
uniform float u_minimumBrightness;
#endif

#ifdef COLOR_CORRECT
uniform vec3 u_hsbShift; // Hue, saturation, brightness
#endif

varying vec3 v_positionMC;
varying vec3 v_positionEC;
varying vec3 v_textureCoordinates;
Expand Down Expand Up @@ -166,6 +170,20 @@ vec4 sampleAndBlend(
return vec4(outColor, outAlpha);
}

vec3 colorCorrect(vec3 rgb) {
#ifdef COLOR_CORRECT
// Convert rgb color to hsb
vec3 hsb = czm_RGBToHSB(rgb);
// Perform hsb shift
hsb.x += u_hsbShift.x; // hue
hsb.y = clamp(hsb.y + u_hsbShift.y, 0.0, 1.0); // saturation
hsb.z = hsb.z > czm_epsilon7 ? hsb.z + u_hsbShift.z : 0.0; // brightness
// Convert shifted hsb back to rgb
rgb = czm_HSBToRGB(hsb);
#endif
return rgb;
}

vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates);
vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float specularMapValue, float fade);

Expand Down Expand Up @@ -285,7 +303,7 @@ void main()

#if defined(FOG) || defined(GROUND_ATMOSPHERE)
const float fExposure = 2.0;
vec3 fogColor = v_fogMieColor + finalColor.rgb * v_fogRayleighColor;
vec3 fogColor = colorCorrect(v_fogMieColor) + finalColor.rgb * colorCorrect(v_fogRayleighColor);
fogColor = vec3(1.0) - exp(-fExposure * fogColor);
#endif

Expand Down Expand Up @@ -321,7 +339,7 @@ void main()
ellipsoidPosition = (czm_inverseView * vec4(ellipsoidPosition, 1.0)).xyz;
AtmosphereColor atmosColor = computeGroundAtmosphereFromSpace(ellipsoidPosition, true);

vec3 groundAtmosphereColor = atmosColor.mie + finalColor.rgb * atmosColor.rayleigh;
vec3 groundAtmosphereColor = colorCorrect(atmosColor.mie) + finalColor.rgb * colorCorrect(atmosColor.rayleigh);
groundAtmosphereColor = vec3(1.0) - exp(-fExposure * groundAtmosphereColor);

fadeInDist = u_nightFadeDistance.x;
Expand Down
60 changes: 60 additions & 0 deletions Specs/Scene/GlobeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,64 @@ defineSuite([
expect(scene).toRender([0, 0, 0, 255]);
});
});

it('renders with hue shift', function() {
var layerCollection = globe.imageryLayers;
layerCollection.removeAll();
layerCollection.addImageryProvider(new SingleTileImageryProvider({url : 'Data/Images/Blue.png'}));

scene.camera.flyHome(0.0);

return updateUntilDone(globe).then(function() {
scene.globe.show = false;
expect(scene).toRender([0, 0, 0, 255]);
scene.globe.show = true;
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).toRenderAndCall(function(rgba) {
scene.globe.atmosphereHueShift = 0.1;
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).notToRender(rgba);
});
});
});

it('renders with saturation shift', function() {
var layerCollection = globe.imageryLayers;
layerCollection.removeAll();
layerCollection.addImageryProvider(new SingleTileImageryProvider({url : 'Data/Images/Blue.png'}));

scene.camera.flyHome(0.0);

return updateUntilDone(globe).then(function() {
scene.globe.show = false;
expect(scene).toRender([0, 0, 0, 255]);
scene.globe.show = true;
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).toRenderAndCall(function(rgba) {
scene.globe.atmosphereSaturationShift = 0.1;
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).notToRender(rgba);
});
});
});

it('renders with brightness shift', function() {
var layerCollection = globe.imageryLayers;
layerCollection.removeAll();
layerCollection.addImageryProvider(new SingleTileImageryProvider({url : 'Data/Images/Blue.png'}));

scene.camera.flyHome(0.0);

return updateUntilDone(globe).then(function() {
scene.globe.show = false;
expect(scene).toRender([0, 0, 0, 255]);
scene.globe.show = true;
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).toRenderAndCall(function(rgba) {
scene.globe.atmosphereBrightnessShift = 0.1;
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).notToRender(rgba);
});
});
});
}, 'WebGL');