Skip to content

Property table custom shader#13163

Open
mzschwartz5 wants to merge 11 commits intogltf-buffers-to-texturefrom
property-table-custom-shader
Open

Property table custom shader#13163
mzschwartz5 wants to merge 11 commits intogltf-buffers-to-texturefrom
property-table-custom-shader

Conversation

@mzschwartz5
Copy link
Contributor

@mzschwartz5 mzschwartz5 commented Jan 26, 2026

Description

**Note: depends on #13155**

This PR adds shader generation logic in the MetadataPipelineStage for binding and sampling property tables (represented as textures).

This is the last PR in a series to support property tables in custom shaders. There are several future follow-ups:

  • Not all property types are supported in custom shaders, but many more useful ones are.
  • Further, this support only extends to WebGL 2.
  • Also out of scope for now - support for updating properties dynamically and having those updates be reflected in custom shaders.
  • Finally, primitives with multiple feature ID sets that access the same property table are unsupported. This could possible be supported in the future (Cesium3DTileset constructor options support specifying a feature ID set).

Also, TODO: update documentation (here, and here). I think that may be a follow-up PR.

Issue number and link

#13124

Testing plan

Testing plan for #13155 still applies - as regression testing.

Additionally, this sandcastle tests actually using a property table in a custom shader to visualize boreholes and modulate their radii based on metadata. The example tileset used has three metadata properties accessible via the shader: drillingDiameter, fromDepth and toDepth (describing the start and end point of each borehole segment to which a drillingDiameter metadata sample applies).

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

@github-actions
Copy link

Thank you for the pull request, @mzschwartz5!

✅ We can confirm we have a CLA on file for you.

@mzschwartz5 mzschwartz5 changed the base branch from main to gltf-buffers-to-texture January 26, 2026 22:27
@mzschwartz5 mzschwartz5 force-pushed the property-table-custom-shader branch from 8780a11 to 725d637 Compare January 28, 2026 16:28
@mzschwartz5 mzschwartz5 mentioned this pull request Jan 28, 2026
6 tasks
@mzschwartz5 mzschwartz5 force-pushed the property-table-custom-shader branch from 725d637 to bcce507 Compare January 28, 2026 20:01
@mzschwartz5 mzschwartz5 force-pushed the property-table-custom-shader branch from bcce507 to d541eae Compare January 29, 2026 00:20
Comment on lines +307 to +310
/**
* Map property tables to feature ID sets for a given primitive. In general, the mapping is not 1:1, but
* within a given primitive it is safe to treat it as such.
*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't always the case... see this sample tileset that explicitly tests multiple feature ID sets for a single primitive.. (Which you can test via the sandcastle linked in the testing steps on the last PR)

However, if a single primitive has multiple feature ID sets, it's ambiguous which one we should use to sample the property table (indexed by (featureID, propertyID)) in the shader. Thus, we just use the first feature ID set we find and log a warning.

There may be a better way to do this in the future, like using an "active" feature ID set or a user-specified one. But this is also a really niche use-case that realistically we don't need to support.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up from the internal discussion: There is https://cesium.com/learn/cesiumjs/ref-doc/Cesium3DTileset.html#featureIdLabel , and one could make a strong case that this, which currently says

Label of the feature ID set to use for picking and styling.

should say

Label of the feature ID set to use for picking and styling and property table access

or something like that.

But... having no clue about how complicated this is (I haven't read the whole changes in all related PRs), this is just a hint, and may be tracked as a possible follow-up for the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I did see that. I would need to look into how that setting would plumb down to the metadata pipeline stage, and how it should be made available for use in a shader (uniform?).

It might be very easy. It's just that, given the scope of these changes already, I think it might be best as a follow-up. I'll add it to the follow-ups listed in the description.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of the changes in this file are just moving code from PropertyTextureProperty.js to this, lower-level class, so that it can be reused by property table properties, which are now also backed by textures.

There are some changes to the moved functions as well, though. May be handy to paste the functions into vscode and run a diff or something.


it("clipping planes cull tiles completely inside clipping region for i3dm", function () {
return Cesium3DTilesTester.loadTileset(
it("clipping planes cull tiles completely inside clipping region for i3dm", async function () {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test became flaky after these changes. Not entirely sure what broke the camel's back, so to speak, but this should be more robust now - waiting for tiles to load before asserting anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, the changes here are mainly just moving tests to go along with the code that was moved.

@mzschwartz5 mzschwartz5 marked this pull request as ready for review January 29, 2026 00:46
@mzschwartz5 mzschwartz5 requested a review from lilleyse January 29, 2026 21:24
@mzschwartz5 mzschwartz5 force-pushed the property-table-custom-shader branch from 7204e11 to 81ccfa0 Compare February 2, 2026 18:36
@mzschwartz5 mzschwartz5 force-pushed the property-table-custom-shader branch from 81ccfa0 to 988b910 Compare February 2, 2026 18:49
@lilleyse
Copy link
Contributor

I confirmed that this is working for instanced and non-instanced models 👍

image

Sandcastle code

@lilleyse
Copy link
Contributor

lilleyse commented Feb 10, 2026

I'm testing with a 3D Tiles 1.0 asset (using b3dm and batch table) and the custom shader doesn't seem to pick up the properties. This might be due to it using batch table JSON instead of batch table binary.

image

Sandcastle code

@lilleyse
Copy link
Contributor

The same error appears on the currently depolyed sandcastle: https://sandcastle.cesium.com/index.html#c=jVLda9swEP9XDj85EORkfevcMEgZFFb6kGxPhlWVzsmt+giS7Kwp/d8nW0qarn0oGJ/ufh9nnU9Y4wP0hHt0cAUG97BET51mv8Za2RRizJfWBE4GXVNMvjamMWJUBlLoMUQp33MKR3EKF9frBLPWWf3TqejGWBWfFdc7hdc88OoNtcqC06HKDdgfb82xdfpc5gUaZDtHmgL16BmXssz8gZhpB2v12p4DjTm6is4Hq1dbLv+//vIMKZ8bA9A6vtFoQqqt8W+4hPsBAOgtyRN+G8dUfs/Jjdl1AVo/ximQsTEVB/1bW4nqlgd0xBXofJgkv+cUYk9leYAt0mY7zDj7MI2Byzg8lpDxSklALZSZXsOXGZtNXs3g1IZJatvOY7TsUVyUczabwiy/hgkl+gugiqRPGIza+XuDdBjD/bQxL/F+xbSofXhSuBiq30jvrAvQxeWIexEw7kXs4auHTjwOP8j7wa6ujpJaUg8krz7YSxCKex+RtlNqRQdsikVdRf4bWZyoJLO569Ep/jRQtvPFj1RkjNVVTN+rgrXqgbszx38

I think that's expected until this PR is merged.

And I checked: This is not caused by the fact that the property is called Height (and not height) 🙂

I checked both as well because I wasn't sure about the property id sanitization rules. But it seems like it should be Height instead of height. I updated the sandcastle.

Property ID Sanitization

GLSL only supports alphanumeric identifiers, i.e. identifiers that do not
start with a number. Additionally, identifiers with consecutive
underscores (__), as well as identifiers with the gl_ prefix, are
reserved in GLSL. To circumvent these limitations, the property IDs are
modified as follows:

  1. Replace all sequences of non-alphanumeric characters with a single _.
  2. Remove the reserved gl_ prefix if present.
  3. If the identifier begins with a digit ([0-9]), prefix with an _

@javagl
Copy link
Contributor

javagl commented Feb 11, 2026

I think that's expected until this PR is merged.

I wasn't entirely sure about that - yesterday, I looked at #10480 and wondered whehther there is anything explicit about the compatibility of "old/legacy" things (like batch tables) with "new" things (like custom shaders). Specifically: Batch tables should work for styling, but I wasn't sure about custom shaders. (I know that there are some translations between them under the hood, but don't know all details)

But it seems like it should be Height instead of height.

Right now, in the shader compliation error message, one can see that the metadata structs only contain _empty, so it's not an issue of case sensitivity (but I assume that when they are not empty, it will have to be Height).

@mzschwartz5
Copy link
Contributor Author

I should add that it's not my intention to add any new features for the legacy metadata workflows. So if they didn't work with custom shaders before, they probably won't now. I only want to make sure I'm not actively breaking any workflows we still support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants