Applying Palette From Texture to Imagery

I’ve been working for some time on getting a branch of Cesium up and running which takes tiles that have raw values baked in and applying a palette to them.

Initially, my approach was to build a clone of UrlTemplateImageryProvider which accepted a colorPalette argument along with a “min” and “max” which defines the boundaries of the data values to display. Given a min/max, the tiler can then bake the values into the PNG’s and Cesium can then apply the colorPalette using WebGL 2D textures. I used a custom TileRenderer class which took care of all of the WebGL stuff. The problem with this approach was that the saved Imagery textures were “paletted” and thus the raw values couldn’t be retrieved from them. This is problematic because I need to generate labels in Cesium which show the value of a coordinate point from the underlying imagery.

This week I saw the “splitDirection” addition to the master branch. I knew immediately that this PR would be immensely helpful in re-organizing my code to no longer use my custom TileRenderer class and instead render the palette on the fly. I’m so close, but I’ve hit a few snags in the process that I’m hoping someone with experience might be able to help with.

The problem:

I need to pass a 2D texture uniform to GlobeFS.glsl’s sampleAndBlend(). Given there are ImageryLayer instances that will have the default (no) color palette, adding a sampler2D texture argument to sampleAndBlend() becomes impossible. The FS compiler won’t allow me to pass any sort of “null” value to sampler2D. “applyColorPalette” gets tripped to true when adding any layers with a color palette and the result is BMNG imagery that has been paletted along with “bindTexture” errors.

In GlobeSurfaceTileProvider.js, I’ve added

            uniformMapProperties.dayTextureColorPalette[numberOfDayTextures] = imageryLayer.colorPalette;
            applyColorPalette = applyColorPalette || uniformMapProperties.dayTextureColorPalette[numberOfDayTextures] !== ImageryLayer.DEFAULT_COLOR_PALETTE;

``

In GlobeSurfaceShaderSet.js, I’ve added

        if (applyColorPalette) {
           fs.defines.push('APPLY_COLOR_PALETTE');
       }

``

and

            computeDayColor += '\

color = sampleAndBlend(\n
color,\n
u_dayTextures[’ + i + ‘],\n
u_dayTextureUseWebMercatorT[’ + i + ‘] ? textureCoordinates.xz : textureCoordinates.xy,\n
u_dayTextureTexCoordsRectangle[’ + i + ‘],\n
u_dayTextureTranslationAndScale[’ + i + '],\n
’ + (applyAlpha ? ‘u_dayTextureAlpha[’ + i + ‘]’ : ‘1.0’) + ',\n
’ + (applyBrightness ? ‘u_dayTextureBrightness[’ + i + ‘]’ : ‘0.0’) + ',\n
’ + (applyContrast ? ‘u_dayTextureContrast[’ + i + ‘]’ : ‘0.0’) + ',\n
’ + (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
’ + (applyColorPalette ? ‘u_dayTextureColorPalette[’ + i + ‘]’ : ‘0.0’) + ‘\n
);\n’;

``

GlobeFS.glsl has these lines added:

#ifdef APPLY_COLOR_PALETTE

uniform sampler2D u_dayTextureColorPalette[TEXTURE_UNITS];

#endif

``

and

vec4 sampleAndBlend(

vec4 previousColor,

sampler2D texture,

vec2 tileTextureCoordinates,

vec4 textureCoordinateRectangle,

vec4 textureCoordinateTranslationAndScale,

float textureAlpha,

float textureBrightness,

float textureContrast,

float textureHue,

float textureSaturation,

float textureOneOverGamma,

float split,

sampler2D textureColorPalette)

{

``

Unfortunately, as I mentioned this doesn’t compile when there is no texture to provide to the sampler2D argument because the #ifdef APPLY_COLOR_PALETTE uniform doesn’t get created.

Is there any way for me to pass a texture to sampleAndBlend and only have it palette the ImageryLayer (texture) that has a defined palette texture, while also not needlessly defining an unused uniform sampler2D?

I appreciate any insight. I’m still stuck on this issue and really need a reliable paletting method done in GLSL that doesn’t impact the generation of the rest of the globe/textures.

Sorry, but I don’t have any good ideas here. Some of the graphics programmers on our team should be able to help here though. I’ll ask around if no one replies.

-Hannah

PR submitted.

https://github.com/AnalyticalGraphicsInc/cesium/pull/4953