Using custom TileMapServiceImageryProvider imagery tile colour and alpha channels to colour terrain based on channel values and desired colour ramp

1. A concise explanation of the problem you’re experiencing.

Cannot apply a material to an ImageryLayer

Cannot use a material on the globe to define fabric with source to access images on a specific imagery layer (or can you?)

2. A minimal code example. If you’ve found a bug, this helps us reproduce and repair it.

N/A

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

We have raster information that we’d like to apply directly to the terrain. Rather than have a fixed colours in the imagery, we’d like to use a channel in the imagery such as alpha to control a ramp between two colours, configurable in the viewer.

For example use alpha channel to control a ramp between blue and red which is applied to the satellite imagery with 50% opacity. (Rather than build in the colour ramp into the source imagery)

As far as i can tell the application of imagery layers has only simple adjustments such as alpha, contrast etc.

There is no way to have a custom GLSL shader for the combination of a layer with other layers.

The function

Cesium.GlobeSurfaceShaderSet.prototype.getShaderProgram = function(options) {…}

``

Applies the surface shader for the globe and defines a GLSL function

vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates)

``

which adds a line to the Fragement shader for each imagerylayer by calling the

vec4 sampleAndBlend(…)

``

function from GlobeFS.glsl

I feel like the only way to achieve what i want is to customise Cesium.GlobeSurfaceShaderSet.prototype.getShaderProgram

I am thinking of defining a GLSL fuction that combines my imagerylayer images with the others similar to sampleAndBlend() with the only difference being it performs an additional step after looking up the colour from the sampler2D for the layer

u_dayTextures[ ]

``

and generates a colour by ramping between two colours using a channel in that texture - eg. alpha

I can identify my layer within the
for (var i = 0; i < numberOfDayTextures; ++i) {…}

``

loop by adding a flag to my imagerylayer
layer.isRaster=true

``

and detecting it in the loop - so i can conditionally apply layer specific shading in this way.

Am I on the right track here or is there an easier way to achieve what i want?

I have also looked at a custom material on the Globe defining a Fabric with source. However in this case i don’t know if i can access the imagerylayer sampler2D. Also it looks like the material on the globe overrides the standard shading.

4. The Cesium version you’re using, your operating system and browser.

Latest Cesium.js

OSX

Chrome

Ok so I have implemented a solution by overriding the following function

Cesium.GlobeSurfaceShaderSet.prototype.getShaderProgram = function(options) {…}

For now i use a slightly customised version of GlobeFS.glsl sampleAndBlend(…) which i apply only to my raster layer. I can then use a channel from the raster layer to control the colour ramp which is combined with the previous layers as usual, maintaining blending, contrast, cutout, yada yada…

This works nicely for me - it would be a nice feature to have in production Cesium.

Glad to hear you have an implementation that works for you! There is an open feature request for this here:

https://github.com/AnalyticalGraphicsInc/cesium/issues/8110

It’d be great if you contribute an implementation of this back into CesiumJS!

Hi Omar

I’ll look at that as it will be useful for the client to have it as a standard feature.