Skip to content

feat(extensions): TerrainExtension GlobeView support#10245

Closed
charlieforward9 wants to merge 1 commit intovisgl:masterfrom
NEW-HEAT:feat/terrain-extension-globe
Closed

feat(extensions): TerrainExtension GlobeView support#10245
charlieforward9 wants to merge 1 commit intovisgl:masterfrom
NEW-HEAT:feat/terrain-extension-globe

Conversation

@charlieforward9
Copy link
Copy Markdown
Collaborator

@charlieforward9 charlieforward9 commented Apr 19, 2026

Summary

Makes TerrainExtension (draped rendering of layers onto a terrain surface) work on GlobeView as well as MapView.

The existing implementation packed layer bounds into the live viewport's common space, which on GlobeView is sphere cartesian — incomparable with screen-space bounds, and invalid as a UV basis for the draped sampler. Cover/height-map FBOs therefore rendered with corrupted UV math on globe.

All bounds are now expressed in absolute Web Mercator common space, regardless of the active projection. The FBO itself is rendered via a WebMercatorViewport in both cases, so the cover/height-map texture becomes projection-invariant — the same draw target can be sampled from MapView and GlobeView without re-rendering, and a projection toggle does not invalidate it.

Changes:

  • projection-utils — new MERCATOR_REFERENCE_VIEWPORT plus helpers lngLatToMercatorCommon and getMercatorReferenceViewport so other modules can compute bounds in the shared absolute-Mercator basis.
  • terrain-cover, height-map-builder — project layer bounds through the Mercator reference viewport. On globe, skip the viewport-bounds intersection in getRenderBounds (which would yield sphere cartesian coords) and use full layer bounds. makeViewport unprojects bounds through the Mercator reference instead of the live viewport for geospatial inputs.
  • shader-module — compute terrainMercPos per-fragment by unprojecting globe cartesian back to lng/lat and forward-projecting through project_mercator_, so USE_HEIGHT_MAP / USE_COVER sample against the absolute-Mercator bounds uniform on any projection. The project module's mercator helpers are VS-only, so the value is passed via varying; terrain meshes are fine enough that interpolation error is negligible. The bounds uniform is packed as absolute Mercator (no commonOrigin subtract) since the shader computes absolute xy itself.

Example app (examples/website/terrain-extension) updated with a MapView/GlobeView toggle so the demo exercises both projections. (Requires TerrainLayer's tesselator: 'grid' from the companion geo-layers PR.)

Why

The docs list _TerrainExtension as experimental, but it's already widely used for draping icons/labels/polygons onto terrain. Extending it to GlobeView lets apps keep the same draped layers across projection toggles without needing a separate code path.

Test plan

  • MapView with TerrainExtension and TerrainLayer source — unchanged behavior
  • GlobeView with TerrainExtension and TerrainLayer(tesselator: 'grid') source — layers drape correctly on sphere
  • Projection toggle without re-rendering the cover/height-map FBO
  • USE_HEIGHT_MAP (elevation offsets for icons/text) correct on both projections
  • USE_COVER (draped overlays on terrain surface) correct on both projections

Companion PRs

Make TerrainExtension's draped rendering (height-map and terrain-cover
FBOs) work on GlobeView as well as MapView. The existing implementation
packed layer bounds into the live viewport's common space, which on
GlobeView is sphere cartesian — incomparable with screen-space bounds,
and invalid as a UV basis for the draped sampler.

All bounds are now expressed in ABSOLUTE Web Mercator common space,
regardless of the active projection. The FBO is rendered via a
WebMercatorViewport in both cases, so the cover/height-map texture is
projection-invariant and a projection toggle no longer requires
re-rendering.

Changes:
- projection-utils: new `MERCATOR_REFERENCE_VIEWPORT` plus helpers
  `lngLatToMercatorCommon` and `getMercatorReferenceViewport` so other
  modules can compute bounds in the shared absolute-Mercator basis.
- terrain-cover, height-map-builder: project layer bounds through the
  Mercator reference viewport; on globe, skip the viewport-bounds
  intersection in `getRenderBounds` (which would yield sphere cartesian
  coords) and use full layer bounds.
- shader-module: compute `terrainMercPos` per-fragment by unprojecting
  globe cartesian back to lng/lat and forward-projecting through
  project_mercator_, so USE_HEIGHT_MAP / USE_COVER samples against the
  absolute-Mercator bounds uniform on any projection. The project
  module's helpers are VS-only, so the value is passed via varying;
  terrain meshes are fine enough that interpolation error is negligible.
  Bounds uniform is packed as absolute Mercator (no commonOrigin
  subtract), since the shader computes absolute xy itself.

Example updated with a GlobeView toggle so the terrain-extension demo
exercises both projections (requires TerrainLayer's grid tesselator from
the companion geo-layers PR.
EOF
)
@charlieforward9
Copy link
Copy Markdown
Collaborator Author

Superseded by #10251 (same branch re-opened under cr/ prefix, pushed directly to visgl/deck.gl).

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.

1 participant