question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

WebGLTile color expression with array

See original GitHub issue

Hi, first of all this is not a bug, it’s a question.

I’m migrating rastersource to webgl and this case the operation I was doing before is:

const RasterSource = source => {
  return new OlRasterSource({
    sources: [source],
    // On every render of the layer the code inside operation will be executed
    operation: function(pixels, data) {
      var pixel = pixels[0];
      if (data.rasterColor || data.palette) {
        var val = getPixelValue(pixel);
        if (val !== 0) {
          if (data.palette) {
            pixel = gradientFunction(pixel[0], data.palette);
          } else {
            pixel = whiteToColorLinearGradient(pixel, data.rasterColor);
          }
        }
      }

      return pixel;
    },
    // LOOK: getRasterSourceLib is a mandatory way of import the functions that will be used inside operation due a compiler issue
    // lib: object with the functions that the worker will receive
    lib: getRasterSourceLib([
      getPixelValue,
      whiteToColorLinearGradient,
      gradientFunction
    ])
  });
};


function gradientFunction(pixel, palette) {
  const color = palette[pixel];
  return [color[0], color[1], color[2], color[3]];
}

I have an object that, depending on the pixel, assigns a colour to it. The palette object is something like:

0: (4) [0, 0, 0, 0] 1: (4) [255, 253, 230, 235] 2: (4) [255, 253, 230, 235] 3: (4) [255, 253, 230, 235] 4: (4) [255, 253, 230, 235] 5: (4) [255, 253, 230, 235] 6: (4) [255, 253, 230, 235] 7: (4) [255, 253, 230, 235] …

My question is how to set an array as a variable:

I have tried this, but it doesn’t work.

const variables = {
    red: palette[("band", 1)][0],
    green: palette[("band", 1)][1],
    blue: palette[("band", 1)][2],
    alpha: 1,  };

  let layer = new TileLayer({
    source: source,
    style: {
      color: [
        "color",
         ["var", "red"],
         ["var", "green"],
         ["var", "blue"],
         ["var", "alpha"]
      ],
      variables: variables
    }
  });

Another attempt is to create the object as a string (a very crazy method).but it doesn’t work

  let caseClausule = `'case',`;
  for (const property in palette) {
    caseClausule += `['==', ['band', 1], ${property}],[${palette[property]}],`;
  }
  caseClausule += `[0,0,0,0]`;

  const variables = {
    caseClausule: caseClausule
  };

  let layer = new TileLayer({
    source: source,
    style: {
      color: [`${caseClausule}`],
      variables: variables
    }
  });

And with this color: ["var", "caseClausule"],I receive the following message

Error: Fragment shader compliation failed: ERROR: 0:23: '=' : dimension mismatch
ERROR: 0:23: 'assign' : cannot convert from 'uniform highp float' to 'highp 4-component vector of float'

Any help, how can I use an array and get some index, for example, in the colour expression instead of single value variables?is it possible?

thanks

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:13 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
mike-000commented, Dec 16, 2021

If dealing with an imported palette object that would need more programming to set up even if there were sufficient non-unique values for it to work, but two interpolates are slightly simpler to set up than nested cases.

const newWebGLTileLayerPalette = (source, palette) => {
  const interpolate = ["interpolate", ["linear"], ["*", ["band", 1], 255]];
  const caseClausules = [interpolate.slice(), interpolate.slice()];

  for (const property in palette) {
    const number = Number(property);
    let caseClausule = caseClausules[Math.floor(number / 128)];
    caseClausule.push(number, [
      palette[property][0],
      palette[property][1],
      palette[property][2],
      palette[property][3] / 255
    ]);
  }

  const caseClausule = [
    "case",
    ["<", ["*", ["band", 1], 255], 127.5],
    caseClausules[0],
    caseClausules[1]
  ];

  let layer = new TileLayer({
    source: source,
    style: {
      color: caseClausule
    }
  });
  return layer;
};
1reaction
mike-000commented, Dec 16, 2021

between is needed - but only because of rounding issues. There is a limit on the number of conditions in a case (at least 128 but less than 256) but you can get around that using nested cases:

const caseClausules = [['case'], ['case']];
const fallback = [0, 0, 0, 0];

for (const property in palette) {
  const number = Number(property);
  let caseClausule = caseClausules[Math.floor(number / 128)];
  caseClausule.push(
    ['between', ['*', ['band', 1], 255], number - 0.5, number + 0.5],
    [palette[property][0], palette[property][1], palette[property][2], 1]
  );
}
caseClausules[0].push(fallback);
caseClausules[1].push(fallback);

const caseClausule = [
  'case',
  ['<', ['*', ['band', 1], 255], 127.5],
  caseClausules[0],
  ['>', ['*', ['band', 1], 255], 127.5],
  caseClausules[1],
  fallback
];
Read more comments on GitHub >

github_iconTop Results From Across the Web

Sea Level (with WebGL) - OpenLayers
The style property of a WebGL tile layer accepts a color expression that can be used to modify pixel values before rendering. Here,...
Read more >
COG + normalize:false + Style Expression: Improve docs
I'm trying to make https://openlayers.org/en/latest/examples/cog-stretch.html work for a COG that has no-data values.
Read more >
Using shaders to apply color in WebGL - Web APIs | MDN
The first thing to do is to establish these colors for the four vertices. To do this, we first need to create an...
Read more >
Cannot declare an array in webgl 1.0 - Stack Overflow
I'm trying to port a shader from glsl 300 es to glsl 100, so it works on more devices. I have an array,...
Read more >
Expressions | Style Specification | Mapbox GL JS
Learn how to write expressions in Mapbox GL JS to style custom data based on a data property and by zoom level.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found