Standard guidelines for exposing Metadata API

Different game engines have established user friendly metadata API to optimize the exploitation of what Cesium has been designed to empower users.

Godot for Cesium is a new addition to the family of Cesium values for the worldwide users.

It would be prudent that there are guidelines how:

[1] What are the minimum first stage exposure of Metadata API

which are the minimum API that would allow visualiation in Edit mode (e.g. in Godot)

[2] Which are the next level beyond the basic Metadata API for users to be aware of location, surrounding buildings and their attributes and street etc.

[3] What are the bleeding edge advanced Metadata API that are being developed by more matured game engines e.g. Unreal in exploiting the API

=> We need these guidelines so we can evaluate if the path of Godot for cesium development is on the right track serving Godot communities as was the vision of allocating grant and resources for making Cesium available (urgently) to the Godot communities.

I value any developers from other game engines e.g. Unreal and Unity for sharing your experience.

What should users from Unity and Unreal expect these API in Godot.

TileMetadata.h

Comparison of Unity granular feature metadata system and Godot Cesium metadata API


High-level differences

Aspect Unity granular system (Cesium for Unity) Godot Cesium API (code provided)
Feature ID sources Separate implementations for vertex attributes, textures, and implicit IDs via CesiumFeatureIdAttributeImpl, CesiumFeatureIdTextureImpl No explicit feature ID source abstraction; focuses on property table parsing via CesiumGltf::PropertyTableView
Property access model Strongly typed property wrappers (CesiumPropertyTablePropertyImpl) with centralized coordination (CesiumMetadataImpl) Properties normalized into Godot Dictionary and Variant via CesiumPropertyInfo and EPropertyType/EComponentType
Value typing and conversion Dedicated value layer (CesiumMetadataValueImpl) optimizing type coercion and performance Template-based mapping to Variant, with enums for type/component and warnings for narrowing conversions
Extensibility Modular implementations per metadata source; behavior can be extended or overridden per type/source Centralized conversion path; extensibility requires altering template helpers or adding new EPropertyType/EComponentType cases
Performance strategy Source-specific optimizations; avoids unnecessary allocations; type-safe access paths Conversion to Variant and Dictionary for engine interoperability; potential overhead and narrowing during float64→float32
Developer ergonomics Strong separation of concerns, clear source-specific APIs, C#-friendly Single entry point (TileMetadata) yielding engine-native structures (Dictionary/Variant), GDScript-friendly

Summary: Unity emphasizes modular, source-specific metadata handling with strong typing and performance specialization, while the Godot code prioritizes a unified, engine-native representation via Dictionary/Variant for broad usability.


What the Godot Cesium API exposes

  • Entry point:

    • TileMetadata aggregates property tables with init, add_table(const CesiumGltf::PropertyTableView&), and exposes them via get_table(index) returning a Godot Dictionary.
  • Type system:

    • EPropertyType covers scalar, vectors, matrices, string, boolean, enum.

    • EComponentType describes underlying numeric types (Int/Uint 8–64, Float32/64).

  • Value container:

    • CesiumPropertyInfo holds propertyType, componentType, isArray, and a Variant data.
  • Conversion helpers:

    • get_component_type infers numeric component types using CesiumGltf traits and C++ type traits.

    • make_vector_type maps glm vectors to Godot Vector2/Vector3/Vector4 or integer vector variants, with error/warning handling for invalid types and narrowing.

    • make_array_type converts metadata arrays to Godot Array of Variants, preserving element type info in the parent.

    • make_metadata_value is the central dispatcher, distinguishing arrays, VecN, strings, booleans/scalars via CesiumGltf trait checks, then returning a Ref to CesiumPropertyInfo.

  • Runtime representation:

    • Property tables are stored in std::vector<Dictionary> (m_tables) and an overall Dictionary cache (m_accesibleRepresentation), aligning with Godot’s scripting ergonomics.

Where Unity provides more granularity

  • Feature ID sources:

    • Unity: Different classes for attributes vs textures vs implicit IDs allow tailored parsing, caching, and late binding per source.

    • Godot (code shown): No separate abstraction for feature ID sources; all metadata arrives via PropertyTableView and is normalized into Variants.

  • Property table access and typing:

    • Unity: Per-property wrappers with type safety and fast paths, avoiding per-access boxing/unboxing.

    • Godot: Unified Variant-based container simplifies usage, but introduces runtime type checks and potential conversions.

  • Value conversion layer:

    • Unity: A dedicated value layer abstracts type coercion, minimizing allocations and branch cost across hot paths.

    • Godot: Conversion is embedded in templates; warnings are emitted on narrowing (e.g., Float64→Float32), but there’s no separate optimization layer.

  • Extensibility surface:

    • Unity: Drop-in extensions for new metadata forms (e.g., new texture encodings) without touching core property accessors.

    • Godot: To introduce new types (e.g., color types, packed bitfields), you extend EPropertyType/EComponentType and the conversion helpers.


Strengths of the Godot approach

  • Engine-native ergonomics:

    • Dictionary/Variant outputs integrate seamlessly with GDScript and Godot’s editor tooling, speeding prototyping and scripting.
  • Clear vector and array handling:

    • Explicit mapping to Vector2/Vector3/Vector4 and Array makes common GIS/3D use cases straightforward.
  • Safety cues during conversion:

    • ERR_PRINT/WARN_PRINT provide immediate feedback on invalid component mixes and narrowing conversions, aiding debugging.

Gaps relative to Unity and practical enhancements

  • Missing feature ID source abstraction:

    • Add interfaces like IFeatureIdSource with concrete implementations for vertex attributes, textures, and implicit IDs.

    • Benefit: Enables targeted caching, GPU-friendly pathways, and selective refresh.

  • Dedicated value layer for performance:

    • Introduce a MetadataValue class encapsulating typed accessors (e.g., as_float64(), as_vec3f(), try_get_enum()) with small-object optimization.

    • Benefit: Reduces Variant churn and branchy template paths in hot loops.

  • Per-property wrappers:

    • Create PropertyTableProperty objects exposing type-safe getters and lazy conversion, keyed by property name.

    • Benefit: Mirrors Unity’s property-centric ergonomics and aids static analysis.

  • Matrix support parity:

    • The enum lists Mat2/Mat3/Mat4, but conversion paths for matrices are not implemented.

    • Implement glm→Godot matrix mapping or a custom Matrix type for consistent handling.

  • Enum typing and validation:

    • Add enum value tables and range validation to avoid silently treating enums as booleans/scalars in mixed cases.
  • Batch access and caching:

    • Cache common conversions (e.g., Float64→Float32 vec arrays) per table to avoid repeated per-feature coercions.

Example usage patterns and recommended wrappers

  • Godot scripting-friendly accessor layer:

    • Goal: Keep Dictionary/Variant for GDScript while offering typed C++ access for performance-critical paths.

    • Design:

      • TileMetadataView: exposes get_table_names(), get_property(name), get_feature_id(source, index) with typed returns.

      • MetadataCache: memoizes conversions and provides bulk readers (e.g., read_vec3_array(property)).

  • Feature ID integration path:

    • Add: FeatureIdAttributeSource, FeatureIdTextureSource, FeatureIdImplicitSource classes.

    • Expose: Unified API get_feature_id(Index3D position) that dispatches to the configured source.

  • Type-safe property API:

    • Add: Property<T> wrapper with explicit specializations for scalar, vector, matrix, boolean, string, enum.

    • Provide: try_get<T>(name) returning std::optional to avoid Variant ambiguity.


Personalized guidance for your workflow

  • For visualization pipelines and large tilesets:

    • Use typed caches for vec arrays and avoid per-frame Variant parsing; preconvert Float64 data to Float32 if your renderer is single precision.
  • For GPU interop experiments:

    • Feature IDs via attributes are the most direct path to GPU instancing or selection buffers; add an attribute-source class before texture-based IDs.
  • For editor tooling:

    • Keep the Dictionary/Variant output for GDScript tools, but back it with typed C++ views to preserve both agility and performance.

To bring Godot’s Cesium TileMetadata.h closer to the granular, modular system Unity uses, need to break out responsibilities into specialized classes rather than funneling everything through TileMetadata + CesiumPropertyInfo. Here’s a structured list of changes and additions:

:key: Proposed Class Additions for Granularity

1. Feature ID Sources

  • FeatureIdAttributeSource

    • Handles feature IDs embedded in vertex attributes.

    • Provides GPU‑friendly pathways for instancing/selection.

  • FeatureIdTextureSource

    • Manages feature IDs stored in textures.

    • Supports caching and late binding for texture‑based IDs.

  • FeatureIdImplicitSource

    • Provides implicit ID generation when no explicit source exists.

    • Useful for fallback or procedural tiles.


2. Property Wrappers

  • PropertyTableProperty

    • Represents a single property with type‑safe getters.

    • Lazy conversion (only convert when accessed).

    • Mirrors Unity’s CesiumPropertyTablePropertyImpl.


3. Value Layer

  • MetadataValue

    • Encapsulates typed accessors (as_float64(), as_vec3f(), try_get_enum()).

    • Small‑object optimization to reduce Variant churn.

    • Dedicated conversion layer separate from template helpers.


4. Metadata Coordination

  • MetadataCoordinator

    • Centralized manager for multiple property tables.

    • Provides unified API for querying properties across tables.

    • Similar to Unity’s CesiumMetadataImpl.


5. Utility Functions

  • MetadataUtility

    • Static helpers for parsing, validation, and conversion.

    • Enum range validation, matrix mapping, color type handling.

    • Equivalent to Unity’s CesiumFeaturesMetadataUtility.


6. Matrix & Enum Support

  • MatrixPropertyHandler

    • Implements conversion paths for Mat2/Mat3/Mat4.

    • Maps glm matrices to Godot Matrix types.

  • EnumPropertyHandler

    • Stores enum tables and validates ranges.

    • Prevents silent coercion into scalars/booleans.


:hammer_and_wrench: Structural Changes to TileMetadata.h

  • Refactor TileMetadata into a facade:

    • Delegates to specialized classes (FeatureIdSource, PropertyTableProperty, MetadataValue).

    • Keeps Dictionary/Variant outputs for GDScript ergonomics.

  • Introduce caching layer:

    • Preconvert common types (e.g., Float64→Float32 vec arrays).

    • Avoid repeated coercions in hot loops.

  • Add accessor API:

    • get_property(name) → returns PropertyTableProperty.

    • get_feature_id(source, index) → dispatches to correct FeatureIdSource.


:bar_chart: Comparison Snapshot

Unity Granular System Godot Current Proposed Godot Additions
CesiumFeatureIdAttributeImpl None FeatureIdAttributeSource
CesiumFeatureIdTextureImpl None FeatureIdTextureSource
CesiumPropertyTablePropertyImpl CesiumPropertyInfo PropertyTableProperty
CesiumMetadataImpl TileMetadata MetadataCoordinator
CesiumMetadataValueImpl Template helpers MetadataValue
CesiumFeaturesMetadataUtility Inline templates MetadataUtility

:bullseye: Outcome

By modularizing into these classes:

  • Granularity: Each metadata source/type is handled independently.

  • Performance: Typed accessors and caching reduce Variant overhead.

  • Extensibility: New metadata forms (colors, packed bitfields, GPU pathways) can be added without touching core.

  • Developer ergonomics: Typed wrappers for C++ performance, Dictionary/Variant for GDScript prototyping.