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

Add simple color-to-alpha for imagery #7727

Merged
merged 1 commit into from
Apr 10, 2019
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
87 changes: 87 additions & 0 deletions Apps/Sandcastle/gallery/Imagery Color To Alpha.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Apply simple color-to-alpha on imagery layers.">
<meta name="cesium-sandcastle-labels" content="Beginner, Tutorials">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
<script type="text/javascript">
if(typeof require === 'function') {
require.config({
baseUrl : '../../../Source',
waitSeconds : 120
});
}
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
#toolbar {
background: rgba(42, 42, 42, 0.8);
padding: 4px;
border-radius: 4px;
}
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<table><tbody>
<tr>
<td>Threshold</td>
<td>
<input type="range" min="0.0" max="1.0" step="0.01" data-bind="value: threshold, valueUpdate: 'input'">
</td>
</tr>
</tbody></table>
</div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer');

var layers = viewer.scene.imageryLayers;

// Set oceans on Bing base layer to transparent
var baseLayer = layers.get(0);
baseLayer.colorToAlpha = new Cesium.Color(0.0, 0.016, 0.059);
baseLayer.colorToAlphaThreshold = 0.2;

// Add a bump layer with adjustable threshold
var singleTileLayer = layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
url : '../images/earthbump1k.jpg',
rectangle : Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0)
}));

singleTileLayer.colorToAlpha = new Cesium.Color(0.0, 0.0, 0.0, 1.0);
singleTileLayer.colorToAlphaThreshold = 0.1;

var viewModel = {
threshold : singleTileLayer.colorToAlphaThreshold
};

Cesium.knockout.track(viewModel);

var toolbar = document.getElementById('toolbar');
Cesium.knockout.applyBindings(viewModel, toolbar);

Cesium.knockout.getObservable(viewModel, 'threshold').subscribe(
function(newValue) {
singleTileLayer.colorToAlphaThreshold = parseFloat(viewModel.threshold);
}
);//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== 'undefined') {
startup(Cesium);
} else if (typeof require === 'function') {
require(['Cesium'], startup);
}
</script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Change Log

##### Additions :tada:
* Added support for the `KHR_texture_transform` glTF extension. [#7549](https://github.com/AnalyticalGraphicsInc/cesium/pull/7549)
* Added support for color-to-alpha with a threshold on imagery layers. [#7727](https://github.com/AnalyticalGraphicsInc/cesium/pull/7727)

##### Fixes :wrench:
* Fixed an error where `clampToHeightMostDetailed` or `sampleHeightMostDetailed` would crash if entities were created when the promise resolved. [#7690](https://github.com/AnalyticalGraphicsInc/cesium/pull/7690)
Expand Down
10 changes: 8 additions & 2 deletions Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ define([
var hasImageryLayerCutout = options.hasImageryLayerCutout;
var colorCorrect = options.colorCorrect;
var highlightFillTile = options.highlightFillTile;
var colorToAlpha = options.colorToAlpha;

var quantization = 0;
var quantizationDefine = '';
Expand Down Expand Up @@ -147,7 +148,8 @@ define([
(cartographicLimitRectangleFlag << 20) |
(imageryCutoutFlag << 21) |
(colorCorrect << 22) |
(highlightFillTile << 23);
(highlightFillTile << 23) |
(colorToAlpha << 24);

var currentClippingShaderState = 0;
if (defined(clippingPlanes) && clippingPlanes.length > 0) {
Expand Down Expand Up @@ -207,6 +209,9 @@ define([
if (showOceanWaves) {
fs.defines.push('SHOW_OCEAN_WAVES');
}
if (colorToAlpha) {
fs.defines.push('APPLY_COLOR_TO_ALPHA');
}

if (enableLighting) {
if (hasVertexNormals) {
Expand Down Expand Up @@ -283,7 +288,8 @@ define([
' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + ',\n\
' + (colorToAlpha ? 'u_colorsToAlpha[' + i + ']' : 'vec4(0.0)') + '\n\
);\n';
if (hasImageryLayerCutout) {
computeDayColor += '\
Expand Down
25 changes: 24 additions & 1 deletion Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,9 @@ define([
u_hsbShift : function() {
return this.properties.hsbShift;
},
u_colorsToAlpha : function() {
return this.properties.colorsToAlpha;
},

// make a separate object so that changes to the properties are seen on
// derived commands that combine another uniform map with this one.
Expand Down Expand Up @@ -1348,6 +1351,7 @@ define([
dayTextureSplit : [],
dayTextureCutoutRectangles : [],
dayIntensity : 0.0,
colorsToAlpha : [],

southAndNorthLatitude : new Cartesian2(),
southMercatorYAndOneOverHeight : new Cartesian2(),
Expand Down Expand Up @@ -1525,7 +1529,8 @@ define([
clippingPlanes : undefined,
clippedByBoundaries : undefined,
hasImageryLayerCutout : undefined,
colorCorrect : undefined
colorCorrect : undefined,
colorToAlpha : undefined
};

function addDrawCommandsForTile(tileProvider, tile, frameState) {
Expand Down Expand Up @@ -1782,6 +1787,7 @@ define([
var applyAlpha = false;
var applySplit = false;
var applyCutout = false;
var applyColorToAlpha = false;

while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) {
var tileImagery = tileImageryCollection[imageryIndex];
Expand Down Expand Up @@ -1860,6 +1866,22 @@ define([
dayTextureCutoutRectangle.w = (cutoutRectangle.north - cartographicTileRectangle.south) * inverseTileHeight;
}

// Update color to alpha
var colorToAlpha = uniformMapProperties.colorsToAlpha[numberOfDayTextures];
if (!defined(colorToAlpha)) {
colorToAlpha = uniformMapProperties.colorsToAlpha[numberOfDayTextures] = new Cartesian4();
}

applyColorToAlpha = defined(imageryLayer.colorToAlpha) && imageryLayer.colorToAlphaThreshold > 0.0;

if (applyColorToAlpha) {
var color = imageryLayer.colorToAlpha;
colorToAlpha.x = color.red;
colorToAlpha.y = color.green;
colorToAlpha.z = color.blue;
colorToAlpha.w = imageryLayer.colorToAlphaThreshold;
}

if (defined(imagery.credits)) {
var credits = imagery.credits;
for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
Expand Down Expand Up @@ -1906,6 +1928,7 @@ define([
surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;
surfaceShaderSetOptions.colorCorrect = colorCorrect;
surfaceShaderSetOptions.highlightFillTile = highlightFillTile;
surfaceShaderSetOptions.colorToAlpha = applyColorToAlpha;

command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(surfaceShaderSetOptions);
command.castShadows = castShadows;
Expand Down
24 changes: 24 additions & 0 deletions Source/Scene/ImageryLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ define([
* @param {Number} [options.maximumTerrainLevel] The maximum terrain level-of-detail at which to show this imagery layer,
* or undefined to show it at all levels. Level zero is the least-detailed level.
* @param {Rectangle} [options.cutoutRectangle] Cartographic rectangle for cutting out a portion of this ImageryLayer.
* @param {Color} [options.colorToAlpha] Color to be used as alpha.
* @param {Number} [options.colorToAlphaThreshold=0.004] Threshold for color-to-alpha.
*/
function ImageryLayer(imageryProvider, options) {
this._imageryProvider = imageryProvider;
Expand Down Expand Up @@ -287,6 +289,20 @@ define([
* @type {Rectangle}
*/
this.cutoutRectangle = options.cutoutRectangle;

/**
* Color value that should be set to transparent.
*
* @type {Color}
*/
this.colorToAlpha = options.colorToAlpha;

/**
* Normalized (0-1) threshold for color-to-alpha.
*
* @type {Number}
*/
this.colorToAlphaThreshold = defaultValue(options.colorToAlphaThreshold, ImageryLayer.DEFAULT_APPLY_COLOR_TO_ALPHA_THRESHOLD);
}

defineProperties(ImageryLayer.prototype, {
Expand Down Expand Up @@ -377,6 +393,14 @@ define([
*/
ImageryLayer.DEFAULT_MAGNIFICATION_FILTER = TextureMagnificationFilter.LINEAR;

/**
* This value is used as the default threshold for color-to-alpha if one is not provided
* during construction or by the imagery provider.
* @type {Number}
* @default 0.004
*/
ImageryLayer.DEFAULT_APPLY_COLOR_TO_ALPHA_THRESHOLD = 0.004;

/**
* Gets a value indicating whether this layer is the base layer in the
* {@link ImageryLayerCollection}. The base layer is the one that underlies all
Expand Down
13 changes: 12 additions & 1 deletion Source/Shaders/GlobeFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];
uniform vec4 u_dayTextureCutoutRectangles[TEXTURE_UNITS];
#endif

#ifdef APPLY_COLOR_TO_ALPHA
uniform vec4 u_colorsToAlpha[TEXTURE_UNITS];
#endif

uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];
#endif

Expand Down Expand Up @@ -115,7 +119,8 @@ vec4 sampleAndBlend(
float textureHue,
float textureSaturation,
float textureOneOverGamma,
float split)
float split,
vec4 colorToAlpha)
{
// This crazy step stuff sets the alpha to 0.0 if this following condition is true:
// tileTextureCoordinates.s < textureCoordinateRectangle.s ||
Expand All @@ -137,6 +142,12 @@ vec4 sampleAndBlend(
vec3 color = value.rgb;
float alpha = value.a;

#ifdef APPLY_COLOR_TO_ALPHA
vec3 colorDiff = abs(color.rgb - colorToAlpha.rgb);
colorDiff.r = max(max(colorDiff.r, colorDiff.g), colorDiff.b);
alpha = czm_branchFreeTernary(colorDiff.r < colorToAlpha.a, 0.0, alpha);
#endif

#if !defined(APPLY_GAMMA)
vec4 tempColor = czm_gammaCorrect(vec4(color, alpha));
color = tempColor.rgb;
Expand Down
45 changes: 45 additions & 0 deletions Specs/Scene/GlobeSurfaceTileProviderSpec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defineSuite([
'Scene/GlobeSurfaceTileProvider',
'Core/Cartesian3',
'Core/Cartesian4',
'Core/CesiumTerrainProvider',
'Core/Color',
'Core/Credit',
Expand Down Expand Up @@ -31,6 +32,7 @@ defineSuite([
], function(
GlobeSurfaceTileProvider,
Cartesian3,
Cartesian4,
CesiumTerrainProvider,
Color,
Credit,
Expand Down Expand Up @@ -590,6 +592,49 @@ defineSuite([
});
});

it('renders imagery with color-to-alpha', function() {
expect(scene).toRender([0, 0, 0, 255]);

var layer = scene.imageryLayers.addImageryProvider(new SingleTileImageryProvider({
url : 'Data/Images/Red16x16.png'
}));

switchViewMode(SceneMode.SCENE3D, new GeographicProjection(Ellipsoid.WGS84));

var layerColor;
return updateUntilDone(scene.globe).then(function() {
expect(scene).toRenderAndCall(function(rgba) {
layerColor = rgba;
// Expect the layer color to be mostly red
expect(layerColor[0]).toBeGreaterThan(layerColor[1]);
expect(layerColor[0]).toBeGreaterThan(layerColor[2]);
});

layer.colorToAlpha = new Color(1.0, 0.0, 0.0);
layer.colorToAlphaThreshold = 0.1;

return updateUntilDone(scene.globe);
})
.then(function() {
var commandList = scene.frameState.commandList;

for (var i = 0; i < commandList.length; ++i) {
var command = commandList[i];

var uniforms = command.uniformMap;
if (!defined(uniforms) || !defined(uniforms.u_dayTextureAlpha)) {
continue;
}

expect(uniforms.u_colorsToAlpha()).toEqual([new Cartesian4(1.0, 0.0, 0.0, 0.1)]);
}

expect(scene).toRenderAndCall(function(rgba) {
expect(rgba).not.toEqual(layerColor);
});
});
});

it('skips layer with uniform alpha value of zero', function() {
var layer = scene.imageryLayers.addImageryProvider(new SingleTileImageryProvider({
url : 'Data/Images/Red16x16.png'
Expand Down