CesiumGS / cesium

An open-source JavaScript library for world-class 3D globes and maps :earth_americas:
https://cesium.com/cesiumjs/
Apache License 2.0
12.85k stars 3.47k forks source link

Support unavailable custom attributes in custom shaders #11071

Open UniquePanda opened 1 year ago

UniquePanda commented 1 year ago

Hi all,

we are already successfully working with custom shaders on our tilesets (3D Tiles). However, one thing that is not fitting our use case is the handling of custom attributes, that are used in the shader but are not actually part of the primitive.
This can easily happen when working with tilesets where you have a defined set of possible attributes, but not all tilesets use all of them.

In such a case, Cesium won't even hand the shader over to compilation, but will disable it beforehand with an error like Primitive is missing attribute <attribute name>, disabling custom vertex shader.

Depending on the number of attributes, it can be quite cumbersome to manage a pre-defined set of shaders with support for all different attributes. Especially if attributes can be freely mixed. Our current workaround is to change the shader text (with string replacement) before adding it to the custom shader. This is generally fine, although not the most beautiful solution. However, this means we now have to add a different custom shader object for every tileset, although for e.g. memory management it would be much nicer to let them share the same object.

Proposed solutions: For some built-in values Cesium adds #defines in the shader code and you can check with #ifdef for their existence. As you can now make sure to only use them in #ifdef blocks, Cesium is not throwing an error if they are not present and lets the shader compile. For custom attributes no #defines are generated, because Cesium obviously can't know what custom attributes could be present.

I came up with two possible solution.

  1. The custom shader object could take an array of strings with all names of "might-be-available" attributes. It would then generate #defines like #define HAS_ATTRIBUTE_<attribute name>. Only if an attribute was not provided via the array, Cesium would throw the usual error.
  2. Cesium keeps searching for all missing attributes, but then automatically adds #defines for them. It would never throw an error because of missing attributes.

Obviously in both cases the developer would be responsible to correctly use #ifdefs. Otherwise, the GLSL compilation would fail anyways.

Do you have an opinion on that? Is this something you'd like to support?

ggetz commented 1 year ago

@ptrgags Would you mind commenting on how this might or might not fit in with the existing custom shader implementation?