Skip to content

Commit 1363dee

Browse files
committed
add simple color-to-alpha for imagery
1 parent 4dc689b commit 1363dee

8 files changed

+201
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
7+
<meta name="description" content="Apply simple color-to-alpha on imagery layers.">
8+
<meta name="cesium-sandcastle-labels" content="Beginner, Tutorials">
9+
<title>Cesium Demo</title>
10+
<script type="text/javascript" src="../Sandcastle-header.js"></script>
11+
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
12+
<script type="text/javascript">
13+
if(typeof require === 'function') {
14+
require.config({
15+
baseUrl : '../../../Source',
16+
waitSeconds : 120
17+
});
18+
}
19+
</script>
20+
</head>
21+
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
22+
<style>
23+
@import url(../templates/bucket.css);
24+
#toolbar {
25+
background: rgba(42, 42, 42, 0.8);
26+
padding: 4px;
27+
border-radius: 4px;
28+
}
29+
</style>
30+
<div id="cesiumContainer" class="fullSize"></div>
31+
<div id="loadingOverlay"><h1>Loading...</h1></div>
32+
<div id="toolbar">
33+
<table><tbody>
34+
<tr>
35+
<td>Threshold</td>
36+
<td>
37+
<input type="range" min="0.0" max="1.0" step="0.01" data-bind="value: threshold, valueUpdate: 'input'">
38+
</td>
39+
</tr>
40+
</tbody></table>
41+
</div>
42+
<script id="cesium_sandcastle_script">
43+
function startup(Cesium) {
44+
'use strict';
45+
//Sandcastle_Begin
46+
var viewer = new Cesium.Viewer('cesiumContainer');
47+
48+
var layers = viewer.scene.imageryLayers;
49+
50+
// Set oceans on Bing base layer to transparent
51+
var baseLayer = layers.get(0);
52+
baseLayer.colorToAlpha = new Cesium.Color(0.0, 0.016, 0.059);
53+
baseLayer.colorToAlphaThreshold = 0.2;
54+
55+
// Add a bump layer with adjustable threshold
56+
var singleTileLayer = layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
57+
url : '../images/earthbump1k.jpg',
58+
rectangle : Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0)
59+
}));
60+
61+
singleTileLayer.colorToAlpha = new Cesium.Color(0.0, 0.0, 0.0, 1.0);
62+
singleTileLayer.colorToAlphaThreshold = 0.1;
63+
64+
var viewModel = {
65+
threshold : singleTileLayer.colorToAlphaThreshold
66+
};
67+
68+
Cesium.knockout.track(viewModel);
69+
70+
var toolbar = document.getElementById('toolbar');
71+
Cesium.knockout.applyBindings(viewModel, toolbar);
72+
73+
Cesium.knockout.getObservable(viewModel, 'threshold').subscribe(
74+
function(newValue) {
75+
singleTileLayer.colorToAlphaThreshold = parseFloat(viewModel.threshold);
76+
}
77+
);//Sandcastle_End
78+
Sandcastle.finishedLoading();
79+
}
80+
if (typeof Cesium !== 'undefined') {
81+
startup(Cesium);
82+
} else if (typeof require === 'function') {
83+
require(['Cesium'], startup);
84+
}
85+
</script>
86+
</body>
87+
</html>
Loading

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Change Log
55

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

910
##### Fixes :wrench:
1011
* 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)

Source/Scene/GlobeSurfaceShaderSet.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ define([
9191
var hasImageryLayerCutout = options.hasImageryLayerCutout;
9292
var colorCorrect = options.colorCorrect;
9393
var highlightFillTile = options.highlightFillTile;
94+
var colorToAlpha = options.colorToAlpha;
9495

9596
var quantization = 0;
9697
var quantizationDefine = '';
@@ -147,7 +148,8 @@ define([
147148
(cartographicLimitRectangleFlag << 20) |
148149
(imageryCutoutFlag << 21) |
149150
(colorCorrect << 22) |
150-
(highlightFillTile << 23);
151+
(highlightFillTile << 23) |
152+
(colorToAlpha << 24);
151153

152154
var currentClippingShaderState = 0;
153155
if (defined(clippingPlanes) && clippingPlanes.length > 0) {
@@ -207,6 +209,9 @@ define([
207209
if (showOceanWaves) {
208210
fs.defines.push('SHOW_OCEAN_WAVES');
209211
}
212+
if (colorToAlpha) {
213+
fs.defines.push('APPLY_COLOR_TO_ALPHA');
214+
}
210215

211216
if (enableLighting) {
212217
if (hasVertexNormals) {
@@ -283,7 +288,8 @@ define([
283288
' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
284289
' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
285290
' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\
286-
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\
291+
' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + ',\n\
292+
' + (colorToAlpha ? 'u_colorsToAlpha[' + i + ']' : 'vec4(0.0)') + '\n\
287293
);\n';
288294
if (hasImageryLayerCutout) {
289295
computeDayColor += '\

Source/Scene/GlobeSurfaceTileProvider.js

+24-1
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,9 @@ define([
13181318
u_hsbShift : function() {
13191319
return this.properties.hsbShift;
13201320
},
1321+
u_colorsToAlpha : function() {
1322+
return this.properties.colorsToAlpha;
1323+
},
13211324

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

13521356
southAndNorthLatitude : new Cartesian2(),
13531357
southMercatorYAndOneOverHeight : new Cartesian2(),
@@ -1525,7 +1529,8 @@ define([
15251529
clippingPlanes : undefined,
15261530
clippedByBoundaries : undefined,
15271531
hasImageryLayerCutout : undefined,
1528-
colorCorrect : undefined
1532+
colorCorrect : undefined,
1533+
colorToAlpha : undefined
15291534
};
15301535

15311536
function addDrawCommandsForTile(tileProvider, tile, frameState) {
@@ -1782,6 +1787,7 @@ define([
17821787
var applyAlpha = false;
17831788
var applySplit = false;
17841789
var applyCutout = false;
1790+
var applyColorToAlpha = false;
17851791

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

1869+
// Update color to alpha
1870+
var colorToAlpha = uniformMapProperties.colorsToAlpha[numberOfDayTextures];
1871+
if (!defined(colorToAlpha)) {
1872+
colorToAlpha = uniformMapProperties.colorsToAlpha[numberOfDayTextures] = new Cartesian4();
1873+
}
1874+
1875+
applyColorToAlpha = defined(imageryLayer.colorToAlpha) && imageryLayer.colorToAlphaThreshold > 0.0;
1876+
1877+
if (applyColorToAlpha) {
1878+
var color = imageryLayer.colorToAlpha;
1879+
colorToAlpha.x = color.red;
1880+
colorToAlpha.y = color.green;
1881+
colorToAlpha.z = color.blue;
1882+
colorToAlpha.w = imageryLayer.colorToAlphaThreshold;
1883+
}
1884+
18631885
if (defined(imagery.credits)) {
18641886
var credits = imagery.credits;
18651887
for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
@@ -1906,6 +1928,7 @@ define([
19061928
surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;
19071929
surfaceShaderSetOptions.colorCorrect = colorCorrect;
19081930
surfaceShaderSetOptions.highlightFillTile = highlightFillTile;
1931+
surfaceShaderSetOptions.colorToAlpha = applyColorToAlpha;
19091932

19101933
command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(surfaceShaderSetOptions);
19111934
command.castShadows = castShadows;

Source/Scene/ImageryLayer.js

+24
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ define([
158158
* @param {Number} [options.maximumTerrainLevel] The maximum terrain level-of-detail at which to show this imagery layer,
159159
* or undefined to show it at all levels. Level zero is the least-detailed level.
160160
* @param {Rectangle} [options.cutoutRectangle] Cartographic rectangle for cutting out a portion of this ImageryLayer.
161+
* @param {Color} [options.colorToAlpha] Color to be used as alpha.
162+
* @param {Number} [options.colorToAlphaThreshold=0.004] Threshold for color-to-alpha.
161163
*/
162164
function ImageryLayer(imageryProvider, options) {
163165
this._imageryProvider = imageryProvider;
@@ -287,6 +289,20 @@ define([
287289
* @type {Rectangle}
288290
*/
289291
this.cutoutRectangle = options.cutoutRectangle;
292+
293+
/**
294+
* Color value that should be set to transparent.
295+
*
296+
* @type {Color}
297+
*/
298+
this.colorToAlpha = options.colorToAlpha;
299+
300+
/**
301+
* Normalized (0-1) threshold for color-to-alpha.
302+
*
303+
* @type {Number}
304+
*/
305+
this.colorToAlphaThreshold = defaultValue(options.colorToAlphaThreshold, ImageryLayer.DEFAULT_APPLY_COLOR_TO_ALPHA_THRESHOLD);
290306
}
291307

292308
defineProperties(ImageryLayer.prototype, {
@@ -377,6 +393,14 @@ define([
377393
*/
378394
ImageryLayer.DEFAULT_MAGNIFICATION_FILTER = TextureMagnificationFilter.LINEAR;
379395

396+
/**
397+
* This value is used as the default threshold for color-to-alpha if one is not provided
398+
* during construction or by the imagery provider.
399+
* @type {Number}
400+
* @default 0.004
401+
*/
402+
ImageryLayer.DEFAULT_APPLY_COLOR_TO_ALPHA_THRESHOLD = 0.004;
403+
380404
/**
381405
* Gets a value indicating whether this layer is the base layer in the
382406
* {@link ImageryLayerCollection}. The base layer is the one that underlies all

Source/Shaders/GlobeFS.glsl

+12-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];
3737
uniform vec4 u_dayTextureCutoutRectangles[TEXTURE_UNITS];
3838
#endif
3939

40+
#ifdef APPLY_COLOR_TO_ALPHA
41+
uniform vec4 u_colorsToAlpha[TEXTURE_UNITS];
42+
#endif
43+
4044
uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];
4145
#endif
4246

@@ -115,7 +119,8 @@ vec4 sampleAndBlend(
115119
float textureHue,
116120
float textureSaturation,
117121
float textureOneOverGamma,
118-
float split)
122+
float split,
123+
vec4 colorToAlpha)
119124
{
120125
// This crazy step stuff sets the alpha to 0.0 if this following condition is true:
121126
// tileTextureCoordinates.s < textureCoordinateRectangle.s ||
@@ -137,6 +142,12 @@ vec4 sampleAndBlend(
137142
vec3 color = value.rgb;
138143
float alpha = value.a;
139144

145+
#ifdef APPLY_COLOR_TO_ALPHA
146+
vec3 colorDiff = abs(color.rgb - colorToAlpha.rgb);
147+
colorDiff.r = max(max(colorDiff.r, colorDiff.g), colorDiff.b);
148+
alpha = czm_branchFreeTernary(colorDiff.r < colorToAlpha.a, 0.0, alpha);
149+
#endif
150+
140151
#if !defined(APPLY_GAMMA)
141152
vec4 tempColor = czm_gammaCorrect(vec4(color, alpha));
142153
color = tempColor.rgb;

Specs/Scene/GlobeSurfaceTileProviderSpec.js

+45
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defineSuite([
22
'Scene/GlobeSurfaceTileProvider',
33
'Core/Cartesian3',
4+
'Core/Cartesian4',
45
'Core/CesiumTerrainProvider',
56
'Core/Color',
67
'Core/Credit',
@@ -31,6 +32,7 @@ defineSuite([
3132
], function(
3233
GlobeSurfaceTileProvider,
3334
Cartesian3,
35+
Cartesian4,
3436
CesiumTerrainProvider,
3537
Color,
3638
Credit,
@@ -590,6 +592,49 @@ defineSuite([
590592
});
591593
});
592594

595+
it('renders imagery with color-to-alpha', function() {
596+
expect(scene).toRender([0, 0, 0, 255]);
597+
598+
var layer = scene.imageryLayers.addImageryProvider(new SingleTileImageryProvider({
599+
url : 'Data/Images/Red16x16.png'
600+
}));
601+
602+
switchViewMode(SceneMode.SCENE3D, new GeographicProjection(Ellipsoid.WGS84));
603+
604+
var layerColor;
605+
return updateUntilDone(scene.globe).then(function() {
606+
expect(scene).toRenderAndCall(function(rgba) {
607+
layerColor = rgba;
608+
// Expect the layer color to be mostly red
609+
expect(layerColor[0]).toBeGreaterThan(layerColor[1]);
610+
expect(layerColor[0]).toBeGreaterThan(layerColor[2]);
611+
});
612+
613+
layer.colorToAlpha = new Color(1.0, 0.0, 0.0);
614+
layer.colorToAlphaThreshold = 0.1;
615+
616+
return updateUntilDone(scene.globe);
617+
})
618+
.then(function() {
619+
var commandList = scene.frameState.commandList;
620+
621+
for (var i = 0; i < commandList.length; ++i) {
622+
var command = commandList[i];
623+
624+
var uniforms = command.uniformMap;
625+
if (!defined(uniforms) || !defined(uniforms.u_dayTextureAlpha)) {
626+
continue;
627+
}
628+
629+
expect(uniforms.u_colorsToAlpha()).toEqual([new Cartesian4(1.0, 0.0, 0.0, 0.1)]);
630+
}
631+
632+
expect(scene).toRenderAndCall(function(rgba) {
633+
expect(rgba).not.toEqual(layerColor);
634+
});
635+
});
636+
});
637+
593638
it('skips layer with uniform alpha value of zero', function() {
594639
var layer = scene.imageryLayers.addImageryProvider(new SingleTileImageryProvider({
595640
url : 'Data/Images/Red16x16.png'

0 commit comments

Comments
 (0)