Repository navigation
Globe projection, exact map camera, underground camera and volumetric clouds story - #17
Merged
Merged
Conversation
Custom layers get a unit-sphere matrix from MapLibre >= 5 and a Mercator matrix plus a globe-to-Mercator matrix from Mapbox >= 3 when rendering a globe, so 3D objects used to end up misplaced on it. Build the projection-view-model matrix for each projection and blend them like the tiles do while the globe fades into Mercator. Derive the camera from that matrix exactly: the real eye position, orientation and a canonical perspective projection with matching fov, aspect, near and far, instead of a point in front of the eye and three.js defaults. Hide what is behind the planet in overlay mode, where the map depth buffer isn't available.
- Pointer rays started from the centre of the near plane instead of the pointer, missing the eye; and offsetX was relative to whatever element was hit, like a marker or a popup inside the map container. - Render in-layer at the map canvas' actual pixel ratio, which differs from devicePixelRatio when the map caps its canvas size. - coordsToVector3 uses the closed-form Mercator northing, and vector3ToCoords is now its exact inverse (it drifted ~10 m at 10 km).
MapLibre >= 5 accepts a maxPitch of up to 180 degrees but pushes the camera back above the ground on every camera update. Lift that constraint while mounted, with an optional floor, and show it in an Underground story that flies through tube tunnels under London.
Ray marched cloud layers carved from GPU-generated Perlin-Worley noise, lit with self shadowing, multiple scattering octaves and the shade of the layers above, and accumulated over frames. Each layer is tuned like a flight simulator weather panel, and the clouds cast shadows on the map.
Mark the ESLint config as root so it doesn't merge with configs further up the tree, and fix the two lint errors.
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.
Globe projection support, an exact map camera, an opt-in underground camera for MapLibre, and a volumetric clouds story.
Library
Globe projection (MapLibre >= 5, Mapbox >= 3). In globe mode, custom layers get a different matrix than in Mercator. MapLibre hands over a unit-sphere matrix. Mapbox hands over a Mercator matrix plus a globe-to-Mercator matrix. The library multiplied either one by a Mercator model matrix, so on a MapLibre globe every object ended up small and clustered in the wrong place.
src/core/projection.tsnow builds the projection-view-model matrix for both projections. While the globe fades into Mercator (MapLibre: zoom 11–12, Mapbox: zoom 5–6), it blends the two matrices the same way the tiles do.<Canvas>,<Coordinates>and raycasting all go through it. Inoverlaymode, a depth-only globe occluder hides objects behind the planet; in-layer mode already gets that from MapLibre's depth buffer.Exact camera.
syncCameranow reads the camera straight from the map matrix:camera.positionis the real eye. Before, it was a point about 2× the near distance in front of it.isPerspectiveMatrixchecks work.fov,aspect,nearandfarmatch the map. They used to be75°andnear: 0.Anything that reads the camera now gets correct values: lighting, drei's
Billboard/Html/calculateScaleFactor, postprocessing that linearises depth.Fixes
offsetX, which is relative to whatever element was hit, e.g. a marker, popup or<Html>inside the map container.maxCanvasSize, 4096px by default) on large retina screens, wheredevicePixelRatiois wrong.coordsToVector3uses the closed-form Mercator northing, andvector3ToCoordsis now its exact inverse. At London's latitude it used to drift about 10 m at 10 km and about 1 km at 100 km.averageMercatorScalestays exported but is exact and no longer grows a cache.CanvasOverlaydisplay name (Mapbox), ESLintroot: true, and the two existing lint errors.UndergroundCamera/allowUndergroundCamera(MapLibre only). MapLibre 5 acceptsmaxPitchup to 180°, but a private step (_elevateCameraIfInsideTerrain) pushes the camera back above ground on every camera change. This lifts it while mounted, with an optionalminAltitudefloor.Mapbox can't do this: it throws for pitch > 85° and clamps the camera above terrain.
Stories
Testing
getMatrixForModeland Mapbox's globe matrix, the transition blend, camera decomposition (off-centre, scaled, below ground, orthographic), pick rays, the Mercator round trip against<Canvas>space, and the underground helper.tsc -p tsconfig.app.json,npm run build,npm run verify:pack(all 6 entry points) and a productionstorybook buildpass. Lint has no errors, and the only new warning source was fixed.Notes for review
VITE_MAPBOX_TOKENneeds a working token to try it. GitHub push protection also flags that token literal, so this PR drops it fromstory-map-storybook.tsx; Storybook's config still injects the same default.calculateScaleFactor(e.g.ScreenSizerin the sunlight story) now gets the size it asked for. Before, it was about 2.3× larger because of the default 75° fov.changeset version), plus the README feature list and npm keywords. Merging it makes the Release workflow publish@wendylabsinc/react-three-map@1.1.0to npm and create the GitHub release.