Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Definition of Feature IDs in EXT_mesh_features #624

Closed
javagl opened this issue Feb 9, 2022 · 2 comments
Closed

Definition of Feature IDs in EXT_mesh_features #624

javagl opened this issue Feb 9, 2022 · 2 comments

Comments

@javagl
Copy link
Contributor

javagl commented Feb 9, 2022

Some structural changes to the EXT_mesh_features extension have been started recently. The largest change is that EXT_mesh_features will now only cover the definition of Feature IDs. (The remaining parts - property tables and property textures - will be moved into a dedicated extension). This includes some changes to the definition of feature IDs:

  • The "Implicit Feature IDs" (that had been defined via offset and repeat) are removed

  • The JSON structure is changed slightly:

    • Previously: The feature IDs had been stored in a meshPrimitive.featureIds array. This array contained either "feature ID attributes" or "feature ID textures". They had been associated with property tables via the propertyTables array that contained property table indices. The Feature ID and the property table had been associated implicitly by "appearing at the same array index".
    • Now: The feature IDs are stored in a dictionary. It contains general "feature ID" objects (that in turn refer to attributes or textures). They explicitly refer to a property table by storing the index of the property table directly
  • The feature ID objects now contain additional properties:

    • The nullFeatureId is a sentinel value that indicates that a certain element is not associated with any feature ID
    • The featureCount indicates how many distinct features there are

The featureCount is supposed to be the the number of unique non-null feature ID values:

  1. For feature IDs like [0,1,null,null,4,5,null], the featureCount would be 4
  2. For feature IDs like [0,1,null,null,4,4,null], the featureCount would be 3

This property and its purpose sparked some discussion.

The property might be useful for a client, in order to create sorts of "mappings". For example, for the first example above, the client might create an array of size 4, and fill it with the feature IDs: [0, 1, 4, 5]. But this array itself then constitutes a mapping from indices to feature ID, although clients might actually rather need the inverse - namely, a mapping from feature IDs to indices (i.e. rows of a property table).

There have been considerations to put some additional constraints on the feature IDs: Instead of allowing them to be "arbitrary, sparse IDs", they could be restricted to be consecutive integers, starting at 0 (aka indices). That could make parts of the implementation and consumption much easier: The featureCount would then simply the the number of indices, knowing that they are in the range [0, featureCount).

Slight generalizations would be possible. For example, these indices could be restricted to a range, by defining a minId and a maxId, which still would allow a direct mapping of these "IDs" to indices. If this option is explored further, there are further questions to consider. For example, the question of whether clients rather need a featureCount or a totalFeatureCount. For example, there might be one property table with 10 rows, and two primitives, where the first one contains feature IDs [0,5), and the second one contains feature IDs [5, 10). For both feature ID sets, the featureCount would be 5, but the totalFeatureCount would be 10.

Constraining the IDs to be indices would no longer allow users to directly store arbitrary values as feature IDs. For example, users might want to store IDs that are used in their custom database system. like [1234, 2345, 3456, 4567] that are then used to look up the corresponding data. The support of this use case right now is also limited by the fact that the feature IDs have to be integers. But it could still be emulated by using Property Tables to store these custom IDs: If users wanted to identify 4 features with their custom IDs, then this could be accomplished with Feature ID values [0,1,2,3] and a property table that contains the actual, corresponding custom IDs, [1234, 2345, 3456, 4567]. The latter, if applied consistently, could even be a generalization of the external lookup concept, because it would allow the users to use, for example, STRING values as their actual, custom IDs.


There has also been the idea of allowing both IDs and indices, and indicate the nature of the IDs explicitly. Very roughly speaking: There could be some sort of boolean featureIdsAreIndices flag that indicates whether these IDs are in fact indices, or sparse, arbitrary ID values. But mixing these fundamentally different concepts - IDs vs. indices - in the same structure might cause confusion.

For some cases, one could consider to directly use the indices of the glTF mesh primitive itself as "feature IDs". But whether there are reasonable use-cases for this (beyond assigning different IDs for each point of a point cloud) has to be investigated.

@lilleyse
Copy link
Contributor

This has mostly been addressed in CesiumGS/glTF#51, but one open question is how runtime engines will support interaction with features defined by global feature IDs.

CesiumJS has the concept of a batch texture which stored colors and show/hide for features, allocated based on the feature count, and so feature IDs are expected to be between [0, count - 1].

With arbitrarily large feature IDs this technique won't work. One solution is to map global feature IDs to local feature IDs before uploading the data to the GPU. This is straightforward for feature ID attributes (though a little costly) but not so straightforward for feature ID textures since the only way to get pixel values is to write the image to a canvas, unless there's some GPGPU technique to consider here.

Another idea that is probably too complex and slow:

I have a rough idea for how CesiumJS would be able to support show/hide/color for global feature IDs without needing to build a mapping upfront, though it would require an O(n) lookup in the shader where n = featureCount

which may not play nicely with WebGL 1 if featureCount is a uniform, though there are tricks to avoid that

Basic idea would be to build the mapping as you go. The batch texture would have two additional textures - global feature ID texture and local feature ID texture - both preallocated with sentinel values. The shader would do globalFeatureIdTexture.indexOf(globalFeatureId) which would give you the index into the local feature ID texture, which would give you the index into the color texture.

The client would be responsible for updating the global feature ID texture and local feature ID texture on demand when a global feature ID's color/show is set.

@javagl
Copy link
Contributor Author

javagl commented Jun 12, 2023

The missing differentiation between "ID" and "index" will cause confusion and will require clients to create different sorts of "mappings". I'd say that that this is more anticipated among JavaScript developers than C/C++/Java developers, depending on how nonchalantly somebody is writing code like value = something[-123]. But for this issue, there is not really an "actionable item" that could cause the issue to be closed. So I'll close it, nonchalantly ...

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

No branches or pull requests

2 participants