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

ImageryLayer.nightAlpha option for night textures #8862

Closed
wants to merge 10 commits into from
Closed
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
64 changes: 64 additions & 0 deletions Apps/Sandcastle/gallery/Night textures on the shade side.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!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="Night textures on the shade side" />
<meta name="cesium-sandcastle-labels" content="Beginner" />
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script
type="text/javascript"
src="../../../Build/CesiumUnminified/Cesium.js"
nomodule
></script>
<script type="module" src="../load-cesium-es6.js"></script>
</head>
<body
class="sandcastle-loading"
data-sandcastle-bucket="bucket-requirejs.html"
>
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar"></div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
"use strict";
//Sandcastle_Begin
var globe = new Cesium.Globe();
globe.enableLighting = true;
globe.dynamicAtmosphereLightingFromSun = true;
globe.showGroundAtmosphere = true;

var clock = new Cesium.Clock({
multiplier: 4000,
shouldAnimate: true,
});

var viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.IonImageryProvider({ assetId: 3845 }),
clockViewModel: new Cesium.ClockViewModel(clock),
globe: globe,
});

var nightLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.IonImageryProvider({ assetId: 3812 })
);

nightLayer.nightAlpha = 1.0; // This sets that nightLayer is only visible on the shade side of the globe//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
startup(Cesium);
}
</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 @@ -23,6 +23,7 @@

##### Additions :tada:

- Added `ImageLayer.nightAlpha` to let render and blend textures only on the shade side of the globe.
- Added `RequestScheduler` to the public API; this allows users to have more control over the requests made by CesiumJS. [#8384](https://github.com/CesiumGS/cesium/issues/8384)
- Added support for high-quality edges on solid geometry in glTF models. [#8776](https://github.com/CesiumGS/cesium/pull/8776)
- Added `Scene.cameraUnderground` for checking whether the camera is underneath the globe. [#8765](https://github.com/CesiumGS/cesium/pull/8765)
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu
- [SungHo Lim](https://github.com/SambaLim)
- [Michael Fink](https://github.com/vividos)
- [Jakub Vrana](https://github.com/vrana)
- [Edvinas Pranka](https://github.com/epranka)
101 changes: 100 additions & 1 deletion Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
var applySaturation = options.applySaturation;
var applyGamma = options.applyGamma;
var applyAlpha = options.applyAlpha;
var applyNightAlpha = options.applyNightAlpha;
var applySplit = options.applySplit;
var showReflectiveOcean = options.showReflectiveOcean;
var showOceanWaves = options.showOceanWaves;
Expand Down Expand Up @@ -151,7 +152,8 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
(imageryCutoutFlag << 22) |
(colorCorrect << 23) |
(highlightFillTile << 24) |
(colorToAlpha << 25);
(colorToAlpha << 25) |
(applyNightAlpha << 26);

var currentClippingShaderState = 0;
if (defined(clippingPlanes) && clippingPlanes.length > 0) {
Expand Down Expand Up @@ -217,6 +219,9 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
if (applyAlpha) {
fs.defines.push("APPLY_ALPHA");
}
if (applyNightAlpha) {
fs.defines.push("APPLY_NIGHT_ALPHA");
}
if (showReflectiveOcean) {
fs.defines.push("SHOW_REFLECTIVE_OCEAN");
vs.defines.push("SHOW_REFLECTIVE_OCEAN");
Expand Down Expand Up @@ -322,6 +327,8 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
(applyAlpha ? "u_dayTextureAlpha[" + i + "]" : "1.0") +
",\n\
" +
(applyNightAlpha ? "u_dayTextureNightAlpha[" + i + "]" : "0.0") +
",\n" +
(applyBrightness ? "u_dayTextureBrightness[" + i + "]" : "0.0") +
",\n\
" +
Expand Down Expand Up @@ -356,6 +363,98 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {

fs.sources.push(computeDayColor);

if (applyNightAlpha) {
var computeNightColor =
"\
vec4 computeNightColor(vec4 initialColor, vec3 textureCoordinates, float nightIntensity)\n\
{\n\
vec4 color = initialColor;\n";

if (hasImageryLayerCutout) {
computeNightColor +=
"\
vec4 cutoutAndColorResult;\n\
bool texelUnclipped;\n";
}

for (var j = 0; j < numberOfDayTextures; ++j) {
if (hasImageryLayerCutout) {
computeNightColor +=
"\
cutoutAndColorResult = u_dayTextureCutoutRectangles[" +
j +
"];\n\
texelUnclipped = v_textureCoordinates.x < cutoutAndColorResult.x || cutoutAndColorResult.z < v_textureCoordinates.x || v_textureCoordinates.y < cutoutAndColorResult.y || cutoutAndColorResult.w < v_textureCoordinates.y;\n\
cutoutAndColorResult = sampleAndBlend(\n";
} else {
computeNightColor += "\
color = sampleAndBlend(\n";
}

computeNightColor +=
"\
color,\n\
u_dayTextures[" +
j +
"],\n\
u_dayTextureUseWebMercatorT[" +
j +
"] ? textureCoordinates.xz : textureCoordinates.xy,\n\
u_dayTextureTexCoordsRectangle[" +
j +
"],\n\
u_dayTextureTranslationAndScale[" +
j +
"],\n\
" +
/* Here is a little trick. We swap the night alpha with alpha and set the night alpha to zero,
it let's to use the same sampleAndBlend function because it thinks that is a normal texture (not night).
Also we recalculate alpha depend on night intensity (inverted diffuse intensity)
*/
"u_dayTextureNightAlpha[" +
j +
"] * nightIntensity * " +
(applyAlpha ? "u_dayTextureAlpha[" + j + "]" : "1.0") +
",\n\
" +
"0.0" +
",\n\
" +
(applyBrightness ? "u_dayTextureBrightness[" + j + "]" : "0.0") +
",\n\
" +
(applyContrast ? "u_dayTextureContrast[" + j + "]" : "0.0") +
",\n\
" +
(applyHue ? "u_dayTextureHue[" + j + "]" : "0.0") +
",\n\
" +
(applySaturation ? "u_dayTextureSaturation[" + j + "]" : "0.0") +
",\n\
" +
(applyGamma ? "u_dayTextureOneOverGamma[" + j + "]" : "0.0") +
",\n\
" +
(applySplit ? "u_dayTextureSplit[" + j + "]" : "0.0") +
",\n\
" +
(colorToAlpha ? "u_colorsToAlpha[" + j + "]" : "vec4(0.0)") +
"\n\
);\n";
if (hasImageryLayerCutout) {
computeNightColor +=
"\
color = czm_branchFreeTernary(texelUnclipped, cutoutAndColorResult, color);\n";
}
}

computeNightColor += "\
return color;\n\
}";

fs.sources.push(computeNightColor);
}

vs.sources.push(getPositionMode(sceneMode));
vs.sources.push(get2DYPositionFraction(useWebMercatorProjection));

Expand Down
13 changes: 13 additions & 0 deletions Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,9 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
u_dayTextureAlpha: function () {
return this.properties.dayTextureAlpha;
},
u_dayTextureNightAlpha: function () {
return this.properties.dayTextureNightAlpha;
},
u_dayTextureBrightness: function () {
return this.properties.dayTextureBrightness;
},
Expand Down Expand Up @@ -1606,6 +1609,7 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
dayTextureTexCoordsRectangle: [],
dayTextureUseWebMercatorT: [],
dayTextureAlpha: [],
dayTextureNightAlpha: [],
dayTextureBrightness: [],
dayTextureContrast: [],
dayTextureHue: [],
Expand Down Expand Up @@ -1802,6 +1806,7 @@ var surfaceShaderSetOptionsScratch = {
applySaturation: undefined,
applyGamma: undefined,
applyAlpha: undefined,
applyNightAlpha: undefined,
applySplit: undefined,
showReflectiveOcean: undefined,
showOceanWaves: undefined,
Expand Down Expand Up @@ -2155,6 +2160,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
var applySaturation = false;
var applyGamma = false;
var applyAlpha = false;
var applyNightAlpha = false;
var applySplit = false;
var applyCutout = false;
var applyColorToAlpha = false;
Expand Down Expand Up @@ -2211,6 +2217,12 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
applyAlpha ||
uniformMapProperties.dayTextureAlpha[numberOfDayTextures] !== 1.0;

uniformMapProperties.dayTextureNightAlpha[numberOfDayTextures] =
imageryLayer.nightAlpha;
applyNightAlpha =
applyNightAlpha ||
uniformMapProperties.dayTextureNightAlpha[numberOfDayTextures] !== 0.0;

uniformMapProperties.dayTextureBrightness[numberOfDayTextures] =
imageryLayer.brightness;
applyBrightness =
Expand Down Expand Up @@ -2362,6 +2374,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
surfaceShaderSetOptions.applySaturation = applySaturation;
surfaceShaderSetOptions.applyGamma = applyGamma;
surfaceShaderSetOptions.applyAlpha = applyAlpha;
surfaceShaderSetOptions.applyNightAlpha = applyNightAlpha;
surfaceShaderSetOptions.applySplit = applySplit;
surfaceShaderSetOptions.enableFog = applyFog;
surfaceShaderSetOptions.enableClippingPlanes = clippingPlanesEnabled;
Expand Down
13 changes: 13 additions & 0 deletions Source/Scene/ImageryLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ import TileImagery from "./TileImagery.js";
* current frame state, this layer, and the x, y, and level coordinates of the
* imagery tile for which the alpha is required, and it is expected to return
* the alpha value to use for the tile.
* @param {Number|Function} [options.nightAlpha=0.0] The alpha blending value of this layer in the shade side of the globe, from 0.0 to 1.0.
* If value is greater than <code>0.0</code>, the layer will be rendered only on the shade side of the globe.
* This only takes effect when <code>enableLighting</code> is true.
* This can either be a simple number or a function with the signature
* <code>function(frameState, layer, x, y, level)</code>. The function is passed the
* current frame state, this layer, and the x, y, and level coordinates of the
* imagery tile for which the alpha is required, and it is expected to return
* the alpha value to use for the tile.
* @param {Number|Function} [options.brightness=1.0] The brightness of this layer. 1.0 uses the unmodified imagery
* color. Less than 1.0 makes the imagery darker while greater than 1.0 makes it brighter.
* This can either be a simple number or a function with the signature
Expand Down Expand Up @@ -131,6 +139,11 @@ function ImageryLayer(imageryProvider, options) {
defaultValue(imageryProvider.defaultAlpha, 1.0)
);

this.nightAlpha = defaultValue(
options.nightAlpha,
defaultValue(imageryProvider.defaultNightAlpha, 0.0)
);

/**
* The brightness of this layer. 1.0 uses the unmodified imagery color. Less than 1.0
* makes the imagery darker while greater than 1.0 makes it brighter.
Expand Down
8 changes: 8 additions & 0 deletions Source/Scene/ImageryProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ function ImageryProvider() {
*/
this.defaultAlpha = undefined;

/**
* The default night alpha blending value of this provider, with 0.0 representing that image is not using for night.
*
* @type {Number}
* @default undefined
*/
this.defaultNightAlpha = undefined;

/**
* The default brightness of this provider. 1.0 uses the unmodified imagery color. Less than 1.0
* makes the imagery darker while greater than 1.0 makes it brighter.
Expand Down
26 changes: 25 additions & 1 deletion Source/Shaders/GlobeFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ uniform bool u_dayTextureUseWebMercatorT[TEXTURE_UNITS];
uniform float u_dayTextureAlpha[TEXTURE_UNITS];
#endif

#ifdef APPLY_NIGHT_ALPHA
uniform float u_dayTextureNightAlpha[TEXTURE_UNITS];
#endif

#ifdef APPLY_SPLIT
uniform float u_dayTextureSplit[TEXTURE_UNITS];
#endif
Expand Down Expand Up @@ -114,13 +118,15 @@ vec4 sampleAndBlend(
vec4 textureCoordinateRectangle,
vec4 textureCoordinateTranslationAndScale,
float textureAlpha,
float textureNightAlpha,
float textureBrightness,
float textureContrast,
float textureHue,
float textureSaturation,
float textureOneOverGamma,
float split,
vec4 colorToAlpha)
vec4 colorToAlpha
)
{
// This crazy step stuff sets the alpha to 0.0 if this following condition is true:
// tileTextureCoordinates.s < textureCoordinateRectangle.s ||
Expand All @@ -135,6 +141,9 @@ vec4 sampleAndBlend(
alphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates);
textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;

// if night alpha is presented, it means that this texture is for night side, so set alpha to zero
textureAlpha = step(textureNightAlpha, 0.0) * textureAlpha;

vec2 translation = textureCoordinateTranslationAndScale.xy;
vec2 scale = textureCoordinateTranslationAndScale.zw;
vec2 textureCoordinates = tileTextureCoordinates * scale + translation;
Expand Down Expand Up @@ -228,6 +237,10 @@ 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 APPLY_NIGHT_ALPHA
vec4 computeNightColor(vec4 initialColor, vec3 textureCoordinates, float nightIntensity);
#endif

void main()
{
#ifdef TILE_LIMIT_RECTANGLE
Expand Down Expand Up @@ -322,9 +335,20 @@ void main()

#ifdef ENABLE_VERTEX_LIGHTING
float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_lightDirectionEC, normalize(v_normalEC)) * 0.9 + 0.3, 0.0, 1.0);
#ifdef APPLY_NIGHT_ALPHA
// Here we blend the night textures depend on diffuse intensity
float nightIntensity = 1.0 - clamp(czm_getLambertDiffuse(czm_lightDirectionEC, normalEC) * 5.0, 0.0, 1.0);
color = computeNightColor(color, clamp(v_textureCoordinates, 0.0, 1.0), nightIntensity);
#endif
vec4 finalColor = vec4(color.rgb * czm_lightColor * diffuseIntensity, color.a);
#elif defined(ENABLE_DAYNIGHT_SHADING)
float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_lightDirectionEC, normalEC) * 5.0 + 0.3, 0.0, 1.0);
#ifdef APPLY_NIGHT_ALPHA
// Here we blend the night textures depend on diffuse intensity
float nightIntensity = 1.0 - clamp(czm_getLambertDiffuse(czm_lightDirectionEC, normalEC) * 5.0, 0.0, 1.0);
color = computeNightColor(color, clamp(v_textureCoordinates, 0.0, 1.0), nightIntensity);
#endif
// continue on diffuse intensity
diffuseIntensity = mix(1.0, diffuseIntensity, fade);
vec4 finalColor = vec4(color.rgb * czm_lightColor * diffuseIntensity, color.a);
#else
Expand Down
2 changes: 2 additions & 0 deletions Specs/Scene/GlobeSurfaceTileProviderSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ describe(
);

layer.alpha = 0.123;
layer.nightAlpha = 0.155;
layer.brightness = 0.456;
layer.contrast = 0.654;
layer.gamma = 0.321;
Expand Down Expand Up @@ -651,6 +652,7 @@ describe(
++tileCommandCount;

expect(uniforms.u_dayTextureAlpha()).toEqual([0.123]);
expect(uniforms.u_dayTextureNightAlpha()).toEqual([0.155]);
expect(uniforms.u_dayTextureBrightness()).toEqual([0.456]);
expect(uniforms.u_dayTextureContrast()).toEqual([0.654]);
expect(uniforms.u_dayTextureOneOverGamma()).toEqual([1.0 / 0.321]);
Expand Down