fix(core): Tile3DLayer renders correctly on GlobeView#10252
Merged
Conversation
7 tasks
7 tasks
felixpalmer
requested changes
Apr 20, 2026
This comment was marked as resolved.
This comment was marked as resolved.
2 tasks
Tile3DLayer (and any other layer using COORDINATE_SYSTEM.METER_OFFSETS) rendered as flat "flaps" sticking out of the sphere on GlobeView because project_position only handled COORDINATE_SYSTEM_LNGLAT in the PROJECTION_MODE_GLOBE branch. METER_OFFSETS positions fell through to the linear project_offset_ path, which treats the meter offsets as raw common-space units rather than as vectors in the ENU tangent frame anchored at the coordinate origin. Attach the tangent plane to the sphere: build the east/north/up basis at the origin in globe common space, scale the meter offsets by GLOBE_RADIUS / EARTH_RADIUS, and add them to the origin position on the globe surface. Each tile now lands at its correct geographic location oriented with the surface. Also update the google-3d-tiles example with a Map/Globe toggle so the fix can be exercised end-to-end against the Google Photorealistic 3D Tiles dataset.
GlobeView.farZ was computed as (altitude + GLOBE_RADIUS*2*scale/height), which pushes the far plane roughly a full globe-diameter beyond the camera. At close zoom this produces a far/near ratio on the order of 40,000:1, which destroys depth-buffer precision and causes z-fighting on 3D features like Tile3DLayer meshes (buildings, terrain surfaces). Replace with the horizon-distance formula sqrt(h^2 + 2*R*h) - the distance from the camera at altitude h to the tangent horizon on a sphere of radius R. Earth's curvature occludes everything beyond that anyway. Keep a 2x multiplier so tall features (mountains, buildings) peeking above the horizon stay in view. At zoom=16 this drops far/near from ~40,000 to ~500, an ~80x boost in depth precision that eliminates visible z-fighting on 3D tile meshes. At zoom=0 the new bound is slightly tighter than before (1.79 vs 2.14), which is fine - the back half of the globe is occluded anyway.
c8125d5 to
c57abbd
Compare
25 tasks
6 tasks
felixpalmer
requested changes
May 12, 2026
felixpalmer
approved these changes
May 13, 2026
Collaborator
Author
|
Let's goooooo! 🏦🏦🏦🏦🏦🏦🏦🏦 |
Collaborator
Author
|
@andreasplesch yes, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
GlobeView.fixes.mov
Fixes two bugs that prevent Tile3DLayer (and any other COORDINATE_SYSTEM.METER_OFFSETS layer) from rendering correctly on GlobeView.
1. METER_OFFSETS on GlobeView — tiles render as flat "flaps"
project_positioninproject.glslonly handledCOORDINATE_SYSTEM_LNGLATinside thePROJECTION_MODE_GLOBEbranch. METER_OFFSETS positions (what loaders.gl 3D Tiles feed us viacartographicModelMatrix+cartographicOrigin) fell through to the linearproject_offset_path, which treats the meter offsets as raw common-space units rather than as vectors in the ENU tangent frame anchored at the coordinate origin. Result: each tile rendered as a flat patch in globe common space, producing the characteristic "folded flaps sticking out of the sphere" look.Fix: in the GLOBE projection branch, build the east/north/up basis at
coordinateOriginin globe common space, scale the meter offsets byGLOBE_RADIUS / EARTH_RADIUS, and add them to the origin position. Each tile now lands at its geographic location oriented with the surface. One shader-level change covers all three Tile3DLayer sub-paths (PointCloudLayer, MeshLayer, ScenegraphLayer) plus any other METER_OFFSETS layer.2. GlobeView far plane wrecks depth precision at close zoom
GlobeView.farZwas(altitude + GLOBE_RADIUS*2*scale/height) * farZMultiplier, which pushes far past the horizon — earth's curvature occludes everything beyond the tangent horizon anyway. At zoom 16 this gives a far/near ratio around 40,000:1, which destroys depth-buffer precision and produces visible z-fighting on 3D features (dark bands cutting across Tile3DLayer meshes).Fix: use the horizon-distance formula
sqrt(h^2 + 2*R*h)for the far plane, keep a 2x multiplier for headroom so tall features (mountains, buildings) peeking above the horizon stay visible. Drops far/near from ~40,000 to ~500 at zoom 16 (~80x depth precision boost). At zoom 0 the new bound is marginally tighter than before (1.79 vs 2.14) — the back half of the globe is occluded anyway.Example
Updated
examples/website/google-3d-tiles/app.jsxwith a Map/Globe toggle so the fix can be exercised end-to-end against the Google Photorealistic 3D Tiles dataset. Initial view state adjusted (minZoom: 0,maxZoom: 24,pitch: 0) so users can zoom all the way out to see the globe and all the way in to see street-level 3D detail.Test plan
yarn buildpassesexamples/website/google-3d-tilesand toggle between Map/Globe