Skip to content

Commit

Permalink
Globe final PR (#3963)
Browse files Browse the repository at this point in the history
* Globe - basic infrastructure, raster layer adaptation for globe (#3783)

* Port changes from main globe branch - basics

Fix minor issues so that it compiles.

* Fix PI redefinitions

* Fix stencil shader

* Port adaptation of raster layer for globe from main globe branch

* Add globe.html example from pheonor's repo

Minor changes (remove terrain, set initial zoom 0, change title and description)

* Better map projection parameter doc comment, warn when using unknown projection

* Mercator projectionData handles negative zoom correctly

* Comment clarification

* Fix spelling of "granularity"

* Add missing docs

* Convert ProjectionBase to an interface

* Do not leak GL object in globe projection error measurement, add a destroy method to projection

* Fix chrome performance warning, refactor error measurement

Warning fixed by changing ring buffer size to 1, making ring buffer pointless, so I removed it.

* Fix granularity capitalization

* Fix capitalization

* Fix typo

* Fix stencil mask triangle index order (this was causing failing render tests)

* Cleanup vertex shader projection interface

* Move projection creation function into its own file

* Remove getProjectionName

* Added comment for deduplicateWrapped

* Remove unused vertex-buffer-related code from image source

* Add globe raster layer render test

* More render tests - test transition to mercator

* Remove pointless test, add test descriptions

* Render test for rendering poles on globe

* SubdivisionGranularitySetting constructor takes an object

* Remove "defines" parameter from useProgram

* Refactor useProgram and Program constructor

* Properly format translatePosMatrix comment

* Refactor globe-specific code outside projection classes, remove stencil-specific granularity settings

* Refactor granularity settings to be more readable

* Minor refactor of ProjectionErrorMeasurement

* Refactor draw_raster.ts

* Move globe utility functions to utils.ts, use easeCubicInOut instead of smoothStep

* Simplify imports in globe.ts

* globe.ts refactor

* Move ProjectionErrorMeasurement to a separate file

* Refactor ProjectionErrorMeasurement

Change parseRGBA8float to a private static function, use isWebGL2 function instead of instanceof

* Refactor draw_raster.ts

* Refactor globe projection error measurement to not use Painter

* Painter.clearStencil creates custom ProjectionData instead of calling getProjectionData(null, null)

* Remove "deduplicateWrapped" functionality from source_cache.ts

* Globe projection no longer requires a map instance

* Painter doesn't pass `this` to `updateGPUdependent`

* isRenderingDirty is now a function

* Rename ProjectionBase to Projection

* Replace globeView property with setGlobeViewAllowed

* Add mercator and globe projection unit tests

* Remove tests that test for exact clipping planes

* Update build test with new bundle size

* isRenderingDirty is now a function

* Globe - fill layer (#3882)

* Port changes from main globe branch - basics

Fix minor issues so that it compiles.

* Fix PI redefinitions

* Fix stencil shader

* Port adaptation of raster layer for globe from main globe branch

* Add globe.html example from pheonor's repo

Minor changes (remove terrain, set initial zoom 0, change title and description)

* Better map projection parameter doc comment, warn when using unknown projection

* Mercator projectionData handles negative zoom correctly

* Comment clarification

* Fix spelling of "granularity"

* Add missing docs

* Convert ProjectionBase to an interface

* Do not leak GL object in globe projection error measurement, add a destroy method to projection

* Fix chrome performance warning, refactor error measurement

Warning fixed by changing ring buffer size to 1, making ring buffer pointless, so I removed it.

* Fix granularity capitalization

* Fix capitalization

* Fix typo

* Fix stencil mask triangle index order (this was causing failing render tests)

* Cleanup vertex shader projection interface

* Move projection creation function into its own file

* Remove getProjectionName

* Added comment for deduplicateWrapped

* Remove unused vertex-buffer-related code from image source

* Add globe raster layer render test

* More render tests - test transition to mercator

* Remove pointless test, add test descriptions

* Render test for rendering poles on globe

* SubdivisionGranularitySetting constructor takes an object

* Remove "defines" parameter from useProgram

* Refactor useProgram and Program constructor

* Properly format translatePosMatrix comment

* Refactor globe-specific code outside projection classes, remove stencil-specific granularity settings

* Refactor granularity settings to be more readable

* Minor refactor of ProjectionErrorMeasurement

* Refactor draw_raster.ts

* Move globe utility functions to utils.ts, use easeCubicInOut instead of smoothStep

* Simplify imports in globe.ts

* globe.ts refactor

* Move ProjectionErrorMeasurement to a separate file

* Refactor ProjectionErrorMeasurement

Change parseRGBA8float to a private static function, use isWebGL2 function instead of instanceof

* Refactor draw_raster.ts

* Refactor globe projection error measurement to not use Painter

* Painter.clearStencil creates custom ProjectionData instead of calling getProjectionData(null, null)

* Remove "deduplicateWrapped" functionality from source_cache.ts

* Globe projection no longer requires a map instance

* Painter doesn't pass `this` to `updateGPUdependent`

* isRenderingDirty is now a function

* Rename ProjectionBase to Projection

* Replace globeView property with setGlobeViewAllowed

* Add mercator and globe projection unit tests

* Remove tests that test for exact clipping planes

* Update build test with new bundle size

* isRenderingDirty is now a function

* Fill, fill-extrusion, line layers, subdivision: Import changes from kubapelc/globe-vector branch

* Fix unit tests

* Subdivision: ensure consistent triangle winding order, fix unit tests

* Fix terrain

* Fix fill extrusion not working with terrain

* Fix typos

* Fix line gradient bug

* Subdivision: fix line ring handling

* Subdivision: fix unit test expecting an invalid line segment

* Fix fill-extrusion ring handling

* Fill-extrusion refactor and fix failing test

* Update terrain fill extrusion test expected image

* Render tests for fill, line and fill-extrusion for globe

* Move fillArrays function into a separate file

* Add vector globe example

* Remove changes for line and fill-extrusion layers to make the PR smaller

* Add unit tests for fillArrays()

* fillArrays unit test has better segment size limits

* Update build test build size

* Fix html example description

* Fix missing docs for granularity settings

* Rename globe fill render test tile source layer to "vector_tiles"

* Fix classifyRings comment format

* Move subdivisionGranularitySettingsNoSubdivision constant to a static readonly field, shorten the name

* Use `import type` for SubdivisionGranularitySetting where possible

* Fix typo

* Revert fill_attributes back to default exports

* Improve comment for scanline subdivision

* Subdivision: break up scanline subdivision function into more functions

* Move SubdivisionGranularitySetting into its own file

* Unit tests: use mock of MercatorProjection instead of the full class

* Add SegmentVector unit tests

* Subdivision: unit tests for poles, ring triangulation, fix bug in ring triangulation

* Subdivision: more pole unit tests

* Subdivision: fix wireframe generation, add unit test for wireframe

* Rename subdivisionGranularitySettings.ts to subdivision_granularity_settings.ts

* Move granularity settings registration to subdivision

* Update build size

* Rename `fillArrays` to `fillLargeMeshArrays`

* Move virtual buffers to a test util file

* Better warning for segments.ts vertex overflow

* Better comment for projection subdivision granularity

* Clarify mesh comparison in fill_large_mesh_arrays.test.ts

* Move mesh creating functions into a separate file, add tests for mesh comparison and grid creation

* Refactor and add better doc comment for `fillLargeMeshArrays`

* Refactor fill_large_mesh_arrays by removing duplicated code

* Move debug functions to mesh_utils.ts

* Unit tests: use StructArrays instead of VirtualVertexBuffer, etc.

* Subdivision: refactor

* Subdivision: rename subdivideFill to subdividePolygon, remove wireframe function

* Subdivision: throw when a vertex is outside int16 range

* Subdivision: refactor generatePoleQuad into a proper function

* Subdivision: add subdivision benchmark

* Subdivision: split scanline subdivision into smaller functions

* Remove wireframe generation function

* Subdivision: better doc comments for scanline subdivision

* Fix 'as any' in segment.ts

* Reuse condition in fill_large_arrays

* Deduplicate code in fill_large_arrays

* Subdivision: remove redundant function in tests

* Subdivision: improve scanline subdivision comments

* Subdivision: benchmark is not async

* Rename SegmentVector's invalidateLast to forceNewSegmentOnTextPrepare

* More tests for segment.ts

* Fix typo in forceNewSegmentOnNextPrepare

* Subdivision: more tests for fillLargeMeshArrays

* Subdivision: better comment in fillLargeMeshArrays

* Fix build due to bad merge.

* Globe - line layer (#3961)

* Fix merge

* Import line layer changes from kubapelc/globe-vector

* Lines: shorten line_bucket.test.ts subdivision settings

* Lines: minor refactor

* Lines: update build size

* Lines: minor refactor

* Globe - fill extrusion layer (#3968)

* Import changes for fill-extrusion from main vector globe branch

* Fill extrusion: refactor

* Fill extrusion: indent shader ifdefs

* Fill extrusion: add example

* Fill extrusion: update build size

* Move globe specific projection methods to projection interface

* Fix failing unit test

* Use vec3.clone() instead of manually copying vector components

* Kubapelc/globe pr hillshade (#3979)

* Import background layer changes from main vector globe branch

* Import hillshade layer changes from main vector globe branch

* Subdivision: explicit types

* Fix single-pixel seams in the oceans

* Add render test for background pattern on globe

* Refactor drawBackground

* Refactor drawHillshade

* Update build size

* Update globe background-pattern render test with results from CI

* Hillshade: refactor prepareHillshade

* Add a render test for fill layer seams fix

* Globe - circle and heatmap layers (#4015)

* Import changes for circle and heatmap layers from the main vector globe branch

* Minor refactors

* Update build size

* Use "/ 8.0" in shader instead of "* 0.125"

* Update shader comments

* Use a thin type instead of full Transform in projection

* Only import types in projection.ts

* getPixelScale and getCircleRadiusCorrection only need map center as argument

* Only import types where possible in projection classes

* Smaller refactors

* Fix failing unit test

* Add heatmap render test

* More explicit types in projection interface

* Globe plane equation is a vec4

* Fix wrong args in projection functions

* Improve readibility of build test and fix it.

* Globe - symbols & symbol bugfixes (#4067)

* Import changes from main vector globe branch

* Fix import

* Remove unused code

* Remove unused imports

* Update build size test

* Remove unused function

* Add render test results for Debian

* Add another Debian render test variant

* Add more render test variants

* Hide collision boxes on the backfacing side of the globe

* Fix pitch-aligned texts getting hidden when their anchor is beyond horizon

* Update build size

* Fix merge

* Better comment in draw_collision_debug

* Update build size

The 10 kb size increase seems to come from the main branch

* Minor refactor

* Use explicit types, even for unused parameters

* Refactor screenspace path projection

* Refactor imports for projection.ts and collision_index.ts

* Fix import in collision_index.ts

* Globe - example images (#4140)

* Add example images

* Add "-" into example name

* Remove basic globe example

* Globe - clipping fix (#4146)

* HiSilicon fix: enable face culling whereever possible

(cherry picked from commit fe439a5)

* Improve circle layer performance by discarding empty pixels

(cherry picked from commit 266897d)

* HiSilicon fix: software clipping of polygon outlines

(cherry picked from commit 98167ba)

* HiSilicon fix: software clipping for line layer

(cherry picked from commit d521e95)

* HiSilicon fix: circle software clipping

(cherry picked from commit f2ed744)

* HiSilicon fix: enable backface culling for symbols

(cherry picked from commit 54e3632)

* Update build test

* Fix terrain using a mirrored projection matrix

* Fix typos

* Fix terrain coord textures being flipped vertically

* Update build size

* Fix rendering of images with face culling, fix image rendering near pole regions

* Add render test for images on a globe

* Update comment in circle.vertex.glsl

* Fix bad merge

* Fix lint

* Fix location of old vertex count

* replace expected file for terrain changes

* Fix rename in main merge branch

* Fix build test

* Move projection to style class (#4267)

* Move projection to style class

* Fix lint

* Fix unit tests

* Increase build size

* Update docs, fix test

* Fix lint

* Add test to cover projection change

* Added more tests

* Add an Atmosphere layer for Globe (#3888) (#4020)

* Port of PoC atmosphere layer.

* Fix resize for draw_atmosphere

* Add some options.

* Allow to change sun date and time

* Fix import warning

* Render atmosphere only when a Globe projection is selected

* Add some comments

* Add some comments

* Change key

* Update changelog

* Fix merge with globe branch

* Fix documentation and default background color.

* Use black clear color only when atmosphere is on

* Use atmosphere uniform for globe position, raidus in camera frame and inv projection matrix.

* Remove unused project method

* Update maplibre-gl-style-spec to 20.3.0 and use sky atmosphere parameter

* Fix globe tests and use light position as Sun position.

* Avoid type name collisions.

* Add atmosphere test for globe projection.

* Update expectedBytes for build test.

* Fix PR comments.

* Update Style test.

* Remove unused method on projection

* Add Sky Test.

* Fix style test and add sky unit test.

* Move getSunPos method

* Fix mercator updateProjection

* Remove isGlobe method and fix merge.

* Fix globe atmosphere tests with new projection style.

* Clean-up some projection and light. Fix setSky and add tests.

* Remove sky test during update.

* Clean-up

* missing fix from merge

* Fix lint

* Terrain fix (#4343)

* Fix missing image for globe example

* Update atmosphere (#4345)

* Merge Sky and Atmosphere code.

* Update changelog

* Fix generate-struct-arrays

* Globe - transform+projection changes (#4341)

* Delete unused file

* Rename projection.name to projection.projectionName

Since this interface will be implemented by the transfrom class soon

* Symbols: displayed collision circles now exactly match their computed positions

* Globe: use mercator projection for symbol placement when globe rendering is disabled

* Group all getters/setters in the transform class

* Transform: move transform-related stuff from the projection interface to transform class

(WIP)

* Transform: finish moving parts of projection into mercator_transform.ts

* Transform: remove posMatrix usage from line symbol placement

(WIP)

* Transform: temporarily remove globe stuff

(WIP, compilable)

* Transform: fix line symbols

* Symbols: fix wrong function names

* Fix line point projections

* Fix line rendering

Some things are still broken

* Fix line symbols sometimes being incorrectly oriented

* Fix some failing unit tests

* Fix single glyph orientation

* Add another image to render test

No idea why it is shifted by a few pixels but I assume that the new expected image is also correct

* Add another expected image to textFit-grid-long test

It was only failing on my machine, works fine in github CI windows tests

* Fix some failing unit tests

* Simplify getProjectionData interface and terrain matrix passing

* Change comment at calculatePosMatrix

* Fix symbols not rendering, remove unused shader parameters

* Bring back globe src files

* globe.test.ts is now globe_transform.test.ts

* Move stuff from globe.ts to globe_transform.ts

* Fix showTileBoundaries not working

Fix the three render tests related to showTileBoundaries timing out.

* Remove irrelevant test

* Fix failing unit test

* Transform: move more stuff from globe to globe_transform

* Transform: better comments

* Transfrom: isRenderingDirty cleanup

* Transform: no more errors in globe_transform.ts

* Transform: remove `get point()` from transform class

* Transform: globe_transform.ts is compilable

* Re-enable globe projection

* Fix source_cache.ts sometimes crashing

* Fix globe.ts - globe_transform.ts circular dependency

* Fix and refactor getProjectionData interface

Now it is actually compilable, with many bugs

* Transform: fix failing unit tests

* Transform: fix symbols not rendering on globe

* Transform: minor fixes

* Transform: update globe symbol render tests

* Transform: unify how symbol/projection.ts exports stuff

* Transform: improve comments

* Remove unused function in painter

* Transform: cleanup unneeded abstract functions

* Transform: replace abstract getHorizon function with more generic isPointOnMapSurface function

* Fix useGlobeRendering not being set properly

* Transform: proper implementation of isPointOnMapSurface and screen pixel unprojection for globe

* Transform: adapt more functions for globe

* Transform: fix locationPoint implementation

* Controls: globe panning experiments

* Controls: reasonable globe panning

* Controls: centering zoom for globe experiment

* Transform: fix globe unit tests

* Transform: fix remaining unit tests

* Move mercator_transform.test to src/geo/projection

* Transform: globe bugfixes and more unit tests

* Transform: bugfix globe setLocationAtPoint

* Transform: isolate accesses to globe projection to avoid unintentional transform's state changes

* Transform: move related tests so they are near each other

* Transform: improve globe unprojection accuracy

* Transform: fix globe bugs

* Transform: move globe unit tests

* Transform: another globe setLocationAtPoint implementation

* Transform: fix globe zoom adjustment not working

* Transform: fix setLocationAtPoint

* Transform: setLocationAtPoint and zoom WIP

* Transform: adjust unit test to accept positive longitudes

* Transform: improve globe math precision (fp64)

* Transform: precision improvement, better camera position

* Transform: another test WIP

* Transform: fix setLocationAtPoint condition

* Transform: more reasonable zoom for globe

Still has bugs though

* Transform: globe zoom works well when cursor is outside the globe

* Transform: globe more consistent zoom logic

* Transform: experimental pole edge clamp for globe

* Transform: fix maxLatitudeForZoomLevel math

* Transform: globe constrain experiment

* Transform: minor improvements

* Transform: globe panning 2.0

* Transform: globe panning 2.1

Adjust more constants!

* Transform: some math for globe zoom

* Transform: globe: working zoom controls without glitches

* Transform: globe zoom: fix some more glitching

* Transform: globe zoom: reduce panning when zoom pixel is far from the planet

* Transform: zoom globe: simplify, better behaviour around poles

* Transform: globe zoom: exact zooming

* Transform: globe zoom: better comments

* Transform: temporarily disable camera easeTo and flyTo

* Transform: calling project/unproject on a globe should fail, rename project/unproject to be more descriptive

* Transform: fitBounds: initial implementation for globe_transform

Not working

* Transform: fitBounds: zoom is now correct

* Transform: fitBounds: padding works for north/south

* Transform: fitBounds: just build on top of mercator code

* Transform: fitBounds: the original way

* Transform: fitBounds: back to mercator-buildon + done

* Transform: tighter bounds for zoom heuristic transition

* Transform: easeTo: probably works

* Transform: attempt to handle camera options apparent zoom for globe

* Transform: easeTo fixes WIP

* Transform: easeTo: mostly working implementation (still WIP)

* Transform: easeTo: small fixes

* Transform: easeTo: intertia works for panning

* Transform: globe zoom: add globe radius based slowing factor

* Transform: globe zoom adjustments

* Transform: jumpTo adapted for globe

* Transform: camera flyTo works for globe

* Make (un)projectToWorldCoordinates into standalone functions

* Fix inertia sometimes rotating in the wrong direction

* Fix transform center sometimes not getting wrapped, leading to visual artifacts

* Transform: easeTo: slerp experiment

* Transform: easeTo: revert slerp, add note on why it is not used

* Transform: improve center animation for easeTo and flyTo

* Minor refactor & remove some outdated TODOs

* More refactor and TODOs

* Transform: globe remembers its globeness state after clone, fixes improper collision box when globe gets soft-disabled

* Terrain matrix refactor WIP

* Terrain fixes

* Transform: better comments, rename angularCoordinatesToVector to angularCoordinatesToSurfaceVector, some functions for globe WIP

* Transform: getBounds for globe works

* Transform: remove some comments

* Fix merge

* Remove globe.test.ts (it is now globe_transform.test.ts)

* Rename Transform.updateProjection to newFrameUpdate

* Revert globe.ts to pre-merge state

* Revert mercator.ts to pre-merge state

* New mechanism for creating specialized transforms, more merge fixes

* Rename projectionMatrix to modelViewProjectionMatrix, refactor mercator_transform.ts a bit

* More merge fixes, minor refactor of transforms

* Add transform getters for atmosphere

* Fix forgotten useGlobeControls uses

* Fix cyclical dependency

* Fix tests

* Fix crashes

* Fix manually triggered globe transition animation

* Fix collision boxes not respecting mercator transition

* Blend out atmosphere when transitioning to mercator

* Fix globe transitions when mercator should be constrained

* Reload all tiles upon projection change

* Fix failing style tests

* Fix terrain source cache tests

* Fix map zoom&center being applied in wrong order, causing zoom to be wrongly constrained under globe

* Update globe pole render tests with correct zoom

* Update globe unit test zooms

* Fix more unit tests

* Fix transform.apply not copying everything, fix globe controls not wrapping longitudes

* Fix some globe tests

* Fix globe setLocationAtPoint

* Fix docs & lint

* Increase globe setLocationAtPoint test desired precision

* Some camera tests for globe

* Fix easeTo test suite name and placing

* Add rotated setLocationAtPoint test for globe, fix failing test

* Fix globe easeTo & flyTo with bearing to follow spec, add tests

* easeTo globe tests

* All relevant camera tests for globe implemented

* Update build size test

* Fix symbols not respecting mercator

* Update build size again

* Terrain fix

* Fix merge

* Fix terrain shaders

* Fix merge

* Revert controls changes

* Fix reverted files

* Fix reverted camera tests

* Revert forgotten file, fix lint

* Update build size

* Feedback comments for unit tests

* Convert setters to functions: runtime code

* Convert setters to functions: test code

* Convert last setter to function

* Fix some tests

* Transform is now an interface

* Rename Transform to ITransform

* Remove abstract functions from transform base class

* TransformHelper wip

* Rename transform files

* Finish transform rewrite

* Fix mercator transform tests

* Fix mercator_transform constructor

* Fix symbol bucket test

* Fix source cache tests

* Fix transform clone bug & tests

* Improve comments

* More comments

* Fix import

* Move helper functions in tests to beginning of file

* Fix collision index test accessing a private field

* Remove unneeded null check

* New utils tests + quadratic solve fix

* Add remapSaturate tests

* Add explicit types to line glyph placement

* Refactor placeGlyphsAlongLine args into an object

* Fix merge, cleanup draw_custom.test, fix missing perspective offset in globe transform

* Fix draw_custom test

* Update build test

* Fix crashes

* Fix transform_helper apply function not setting bearing correctly

* Add test for TransformHelper

* Fix TransformHelper.apply

* Fix flipped text placement

* Add new expected image to render test

* Fix marker tests

* Update build size

* Move functions from mercator_transform.ts to mercator_utils.ts

* Refactor un/projectToWorldCoordinates function args

* Make zoomScale and scaleZoom standalone functions

* Fix unprojectFromWorldCoordinates arg type

* Move globe functions to separate file

* Fix private member access in source_cache.test.ts

* Fix deck.gl missing dot

* Fix missing globe_utils.ts

* Better `angleToRotateBetweenVectors2D` doccomment

* Remove unneeded `protected`

* Cleanup transform interface and remove duplicate comments

* Split mercator_utils tests into a separate file

* Fix tests

* Split globe locationPoint tests a bit

* Add more mercator tests

* More globe tests

* Fix globe getBounds and add tests for it

* Remove unneeded function, update build size

* projectTileCoordinates for globe now covered by test

* Add globe_utils tests

* Split up globe tests more

* Fix missing doccomment

* Rename transform's projection/unprojection functions

* Better ray intersection comment and type

* Reduce indentation

* Improve unproject math readability

* Add point-plane distance util function

* Move tileCoordinatesToMercatorCoordinates to mercator_utils

* Better name for location to mercator coordinate functions

* Move angleToRotateBetweenVectors2D to utils

* Refactor _globeness usage

* Remove _initialized from GlobeTransform

* Remove translatePosition from transform interface

* Add IReadonlyTransform interface

* Update build size

* Remove unneeded comment

* Fix painter test

* Fix lint

* Update test/build/min.test.ts

* Update changelog

* Globe - camera controls (#4408)

* Camera controls changes from dev branch

* Move stuff from globe_control_utils to globe_utils

* Better globe_utils comments

* Fix markers not being updated when globe is toggled

* Fix globe tests

* Update build size

* Better comments for camera helper functions

* Move camera helper functions to beginning of file

* Camera: more and better comments

* Update build size

* Fix globe transform error correction handling

* Better comments for _last* fields in globe transform

* Refactor newFrameUpdate

* Better comments for CoveringTilesOptions type members.

* Refactor globe camera tests to use more describe statements

* Remove isTilePositionOccluded function from transform interface

* Fix camera tests

* Add more mercator_utils test

* Add more globe_transform tests

* Fix failing render tests

* Make camera helper functions static

* Remove `around` from flyTo options.

* Update build size

* CameraHelper: initial implementation, inertia handling

* Move createVec* functions to util.ts

* CameraHelper: panning and zooming

* CameraHelpers: implement cameraForBounds

* CameraHelpers: handle jumpTo

* CameraHelper: easeTo

* CameraHelper: flyTo

* Projection event contains new projection name and is fired by changing style's projection

* Fix lint

* Fix test camera/map not having proper CameraHelper

* Fix easeTo not emitting zoom events

* Fix cameraForBoxAndBearing globe not returning anything, rename camera helter types

* Fix globe easeTo ignoring offset

* Fix one flyTo test not creating camera properly

* Update build size

* Add projection transition event tests

* Add example on how to compensate for how globe size changes with latitude

* Revert scrollzoom delete removal

* Remove apparentZoom parameter

* CameraHelper is set in camera constuctor

* Use spy for projection event unit tests

* Remove unnecessary done() in tests

* Update build size

* Remove more unneeded done() calls

* Do not use map.once callback in projection events tests

* Better zoom delta example title and description

* Rename globe zoom delta and planet size function example

* Add zoom planet size function example image

* Reduce size of some globe example images using compresspng

* Globe: bugfixes: raster layer & projection change (#4546)

* Port bugfix changes

* Update build size

* Fix render tests

* Add render test result for debian

* Increase raster tile granularity some more

* Adjust warped raster tile render test

* Add missing tsdoc param

* Use single checkerboard image for render test

* Globe examples now use setProjection

* Add new raster-pole render test image

* Add another raster-warped expected image

* Use "style.load" event on map instead of on style

* Adapt new heatmap code for globe, update build size

* Fix render tests

Most tests had subpixel shifts

* Globe - custom layers API and examples, globe dev guide (#4577)

* Port custom layer changes and globe docs

* Port transform changes

* Fix custom layer unit test

* Fix failing render tests

* Update build size

* Update globe custom layer example descritions, remove forgotten code

* Remove unused util function

* Incorporate globe docs feedback

* Refactor and expose tile mesh generation

* Refactor custom layers to get smaller args object and access map transform directly

* Simplify more of the custom layer API

* Clean up and adapt more examples

* Fix mercator matrix precision

* Fix 3D model on terrain example

* Rename projectionDataForMercatorCoords to defaultProjectionData

* Document ProjectionData type

* Update build size

* Update developer-guides/globe.md

Co-authored-by: Harel M <harel.mazor@gmail.com>

* Decouple ProjectionData from rendering code

Rename fields to camelCase, move it to a separate file

* Rename ProjectionData members

* Fix mercator transform unit tests

* Add an example to createTileMesh

* Rename CustomRenderMethodInput.shader to shaderData

* Add shaderData examples

* Document TileMesh and CreateTileMeshOptions types

* Fix custom layers in render tests

* Update render tests

Fails other than raster-warped were caused by increasing pos matrix precision in mercator_transform to 64 bit floats

* Add render test result from linux

* Update build size

* Update src/render/program/projection_program.ts

Co-authored-by: Harel M <harel.mazor@gmail.com>

* Rename createTileMeshInternal to createTileMeshWithBuffers

* Update build size

* Improve doc comments

---------

Co-authored-by: Harel M <harel.mazor@gmail.com>

* Globe - Covering tiles (#4615)

* Import coveringTiles changes from dev branch

* Remove duplicated tiles used in render tests

* Remove unused function

* Fix typo

* Properly handle tile wraps and LOD across antimeridian

* Discard previous changes and use custom wrap values instead

* Update build size

* Add render test for LOD at antimeridian

* Convert visibility numbers to enum

* Refactor globe covering tiles into a separate file

* Add yet another raster-warped expected image

* Add unit tests for globe covering tiles

* Refactor globe coveringTiles math to assume worldSize=1 instead of tileSize=1

* Split globe coveringTiles into more functions

* Explain radiusOfMaxLvlLodInTiles value

* Explain why checking 4 tile corners is (mostly) enough to construct an AABB.

* Move mercator coveringTiles into a separate file

* Yet another raster-warped expected image

* Remove ITileVisibilityProvider interface

* Use explicit types

* PR feedback

* Rename coveringTiles stack types

* fix typo

* Remove sky disabling in examples as this is no longer needed.

* Fix spelling

* Fix spelling - unencode

* Fix more spelling

* Fix lint

* Update CHANGELOG.md

---------

Co-authored-by: Jakub Pelc <57600346+kubapelc@users.noreply.github.com>
Co-authored-by: Larrieu Vivian <vivian.larrieu@gmail.com>
Co-authored-by: Jakub Pelc <jakub.pelc@email.cz>
  • Loading branch information
4 people authored Sep 30, 2024
1 parent 2a17350 commit a283af1
Show file tree
Hide file tree
Showing 385 changed files with 24,019 additions and 3,240 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## main

### ✨ Features and improvements
- Support globe mode ([#3963](https://github.com/maplibre/maplibre-gl-js/issues/3963))
- Merge atmosphere an sky implementation ([#3888](https://github.com/maplibre/maplibre-gl-js/issues/3888))
- Add option to display a realistic atmosphere when using a Globe projection ([#3888](https://github.com/maplibre/maplibre-gl-js/issues/3888))
- _...Add new stuff here..._

### 🐞 Bug fixes
Expand Down
2 changes: 1 addition & 1 deletion build/generate-doc-images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async function createImage(exampleName) {
try {
await page.waitForFunction('map.loaded()');
// Wait for 5 seconds on 3d model examples, since this takes longer to load.
const waitTime = exampleName.includes('3d-model') ? 5000 : 1500;
const waitTime = (exampleName.includes('3d-model') || exampleName.includes('globe')) ? 5000 : 1500;
console.log(`waiting for ${waitTime} ms`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} catch (err) {
Expand Down
Binary file added developer-guides/assets/floats.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added developer-guides/assets/no_subdivision.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added developer-guides/assets/wireframe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
195 changes: 195 additions & 0 deletions developer-guides/globe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Globe projection

This guide describes the inner workings of globe projection.
Globe draws the same vector polygons and lines as mercator projection,
ensuring a clear, unstretched image at all view angles and support for dynamic layers and geometry.

The actual projection is done in three steps:

- compute angular spherical coordinates from source web mercator tile data
- convert spherical coordinates to a 3D vector - a point on the surface of a unit sphere
- project the 3D vector using a common perspective projection matrix

So the globe is a unit sphere from the point of view of projection.
This also simplifies a lot of math, and is used extensively in the globe transform class.

Geometry is projected to the sphere in the vertex shader.

## Zoom behavior

To stay consistent with web mercator maps, globe is automatically enlarged when map center is nearing the poles.
This keeps the map center visually similar to a mercator map with the same x,y and zoom.
However, when panning the globe or performing camera animations,
we do not want the planet to get larger or smaller when changing latitudes.
Map movement thus compensates for the planet size change by also
changing zoom level along with latitude changes.

This behavior is completely automatic and transparent to the user.
The only case when the user needs to be aware of this is when
programmatically triggering animations such as `flyTo` and `easeTo`
and using them to both change the map center's latitude and *at the same time*
changing the map's zoom to an amount based on the map's starting zoom.
The example [globe-zoom-planet-size-function](https://maplibre.org/maplibre-gl-js/docs/examples/globe-zoom-planet-size-function/) demonstrates how to
compensate for planet size changes in this case.
All other camera animations (that either specify target zoom
that is not based on current zoom or do not specify zoom at all) will work as expected.

## Shaders

Most vertex shaders use the `projectTile` function, which
accepts a 2D vector of coordinates inside the currently drawn tile,
in range 0..EXTENT (8192), and returns its final projection that can
be directly passed to `gl_Position`.
When drawing a tile, proper uniforms must be set to convert from
these tile-local coordinates to web mercator.

The implementation of `projectTile` is automatically injected into the shader source code.
Different implementations can be injected, depending on the currently active projection.
Thanks to this many shaders use the exact same code for both mercator and globe,
although there are shaders that use `#ifdef GLOBE` for globe-specific code.

## Subdivision

If we were to draw mercator tiles with globe shaders directly, we would end up with a deformed sphere.
This is due to how polygons and lines are triangulated in MapLibre - the earcut algorithm
creates as few triangles as possible, which can sometimes result in huge triangles, for example in the oceans.
This behavior is desirable in mercator maps, but if we were to project the vertices of such large triangles to globe directly,
we would not get curved horizons, lines, etc.
For this reason, before a tile is finished loading, its geometry (both polygons and lines) is further subdivided.

The figure below demonstrates how globe would look without subdivision.
Note the deformed oceans, and the USA-Canada border that is not properly curved.

![](assets/no_subdivision.png)

It is critical that subdivision is as fast as possible, otherwise it would significantly slow down tile loading.
Currently the fastest approach seems to be taking the output geometry from `earcut` and subdividing that further.

When modifying subdivision, beware that it is very prone to subtle errors, resulting in single-pixel seams.
Subdivision should also split the geometry in consistent places,
so that polygons and lines match up correctly when projected.

We use subdivision that results in a square grid, visible in the figure below.

![](assets/wireframe.png)

Subdivision is configured in the Projection object.
Subdivision granularity is defined by the base tile granularity and minimal allowed granularity.
The tile for zoom level 0 will have base granularity, tile for zoom 1 will have half that, etc.,
but never less than minimal granularity.

The maximal subdivision granularity of 128 for fill layers is enough to get nicely curved horizons,
while also not generating too much new geometry and not overflowing the 16 bit vertex indices used throughout MapLibre.

Raster tiles in particular need a relative high base granularity, as otherwise they would exhibit
visible warping and deformations when changing zoom levels.

## Floating point precision & transitioning to mercator

Shaders work with 32 bit floating point numbers (64 bit are possible on some platforms, but very slow).
The 23 bits of mantissa and 1 sign bit can represent at most around 16 million values,
but the circumference of the earth is roughly 40 000 km, which works out to
about one float32 value per 2.5 meters, which is insufficient for a map.
Thus if we were to use globe projection at all zoom levels, we would unsurprisingly encounter precision issues.

![](assets/floats.png)

To combat this, globe projection automatically switches to mercator projection around zoom level 12.
This transition is smooth, animated and can only be noticed if you look very closely,
because globe and mercator projections converge at high zoom levels, and around level 12
they are already very close.

The transition animation is implemented in the shader's projection function,
and is controlled by a "globeness" parameter passed from the transform.

## GPU "atan" error correction

When implementing globe, we noticed that globe projection did not match mercator projection
after the automatic transition described in previous section.
This mismatch was very visible at certain latitudes, the globe map was shifted north/south by hundreds of meters,
but at other latitudes the shift was much smaller. This behavior was also inconsistent - one would
expect the shift to gradually increase or decrease with distance from equator, but that was not the case.

Eventually, we tracked this down to an issue in the projection shader, specifically the `atan` function.
On some GPU vendors, the function is inaccurate in a way that matches the observed projection shifts.

To combat this, every second we draw a 1x1 pixel framebuffer and store the `atan` value
for the current latitude, asynchronously download the pixel's value, compare it with `Math.atan`
reference, and shift the globe projection matrix to compensate.
This approach works, because the error is continuous and doesn't change too quickly with latitude.

This approach also has the advantage that it works regardless of the actual error of the `atan`,
so MapLibre should work fine even if it runs on some new GPU in the future with different
`atan` inaccuracies.

## Clipping

When drawing a planet, we need to somehow clip the geometry that is on its backfacing side.
Since MapLibre uses the Z-buffer for optimizing transparency drawing, filling it with custom
values, we cannot use it for this purpose.

Instead, we compute a plane that intersects the horizons, and for each vertex
we compute the distance from this plane and store it in `gl_Position.z`.
This forces the GPU's clipping hardware to clip geometry beyond the planet's horizon.
This does not affect MapLibre's custom Z values, since they are set later using
`glDepthRange`.

However this approach does not work on some phones due to what is likely a driver bug,
which applies `glDepthRange` and clipping in the wrong order.
So additionally, face culling is used for fill and raster layers
(earcut does not result in consistent winding order, this is ensured during subdivision)
and line layers (which have inconsistent winding order) discard beyond-horizon
pixels in the fragment shader.

## Raster tiles

Drawing raster tiles under globe is somewhat more complex than under mercator,
since under globe they are much more prone to having slight seams between tiles.
Tile are drawn as subdivided meshes instead of simple quads, and the curvature
near the edges can cause seams, especially in cases when two tiles of different
zoom levels are next to each other.

To make sure that there are both no seams and that every pixel is covered by
valid tile texture (as opposed to a stretched border of a neighboring tile),
we first draw all tiles *without* border, marking all drawn pixels in stencil.
Then, we draw all tiles *with* borders, but set stencil to discard all pixels
that were drawn in the first pass.

This ensures that no pixel is drawn twice, and that the stretched borders
are only drawn in regions between tiles.

## Symbols

Symbol rendering also had to be adapted for globe, as well as collision detection and placement.
MapLibre computed well-fitting bounding boxes even for curved symbols under globe projection
by computing the AABB from a projection of the symbol's box' corners and box edge midpoints.
This is an approximation, but works well in practice.

## Transformations and unproject

Most projection and unproject functions from the transform interface are adapted for globe,
with some caveats.
The `setLocationAtPoint`function may sometimes not find a valid solution
for the given parameters.
Globe transform currently does not support constraining the map's center.

## Controls

Globe uses slightly different controls than mercator map.
Panning, zooming, etc. is aware of the sphere and should work intuitively,
as well as camera animations such as `flyTo` and `easeTo`.

Specifically, when zooming, the location under the cursor stays under the cursor,
just like it does on a mercator map.
However this behavior has some limitations on the globe.
In some scenarios, such as zooming to the edge of the planet,
this way of zooming would result in rapid and unpleasant map panning.
Thus this behavior is slowly faded out at low zooms and replaced with an approximation.

There are also other edge cases, such as when looking at the planet's poles
and trying to zoom in to a location that is on the other hemisphere ("behind the pole").
MapLibre does not support moving the camera across poles, so instead we need to rotate around.
In this case, an approximation instead of exact zooming is used as well.

Globe controls also use panning inertia, just like mercator.
Special care was taken to keep the movement speed of inertia consistent.
Binary file added docs/assets/examples/globe-3d-model.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/examples/globe-atmosphere.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/examples/globe-custom-simple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/examples/globe-custom-tiles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/examples/globe-fill-extrusion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/examples/globe-vector-tiles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/data/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {ImagePosition} from '../render/image_atlas';
import type {CanonicalTileID} from '../source/tile_id';
import type {VectorTileFeature, VectorTileLayer} from '@mapbox/vector-tile';
import Point from '@mapbox/point-geometry';
import type {SubdivisionGranularitySetting} from '../render/subdivision_granularity_settings';

export type BucketParameters<Layer extends TypedStyleLayer> = {
index: number;
Expand All @@ -26,6 +27,7 @@ export type PopulateParameters = {
patternDependencies: {};
glyphDependencies: {};
availableImages: Array<string>;
subdivisionGranularity: SubdivisionGranularitySetting;
};

export type IndexedFeature = {
Expand Down
98 changes: 69 additions & 29 deletions src/data/bucket/circle_bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ import type Point from '@mapbox/point-geometry';
import type {FeatureStates} from '../../source/source_state';
import type {ImagePosition} from '../../render/image_atlas';
import type {VectorTileLayer} from '@mapbox/vector-tile';
import {CircleGranularity} from '../../render/subdivision_granularity_settings';

const VERTEX_MIN_VALUE = -32768; // -(2^15)

// Extrude is in range 0..7, which will be mapped to -1..1 in the shader.
function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
// We pack circle position and extrude into range 0..65535, but vertices are stored as *signed* 16-bit integers, so we need to offset the number by 2^15.
layoutVertexArray.emplaceBack(
(x * 2) + ((extrudeX + 1) / 2),
(y * 2) + ((extrudeY + 1) / 2));
VERTEX_MIN_VALUE + (x * 8) + extrudeX,
VERTEX_MIN_VALUE + (y * 8) + extrudeY);
}

/**
Expand Down Expand Up @@ -82,12 +87,21 @@ export class CircleBucket<Layer extends CircleStyleLayer | HeatmapStyleLayer> im
let circleSortKey = null;
let sortFeaturesByKey = false;

// Heatmap circles are usually large (and map-pitch-aligned), tessellate them to allow curvature along the globe.
let subdivide = styleLayer.type === 'heatmap';

// Heatmap layers are handled in this bucket and have no evaluated properties, so we check our access
if (styleLayer.type === 'circle') {
circleSortKey = (styleLayer as CircleStyleLayer).layout.get('circle-sort-key');
const circleStyle = (styleLayer as CircleStyleLayer);
circleSortKey = circleStyle.layout.get('circle-sort-key');
sortFeaturesByKey = !circleSortKey.isConstant();

// Circles that are "printed" onto the map surface should be tessellated to follow the globe's curvature.
subdivide = subdivide || circleStyle.paint.get('circle-pitch-alignment') === 'map';
}

const granularity = subdivide ? options.subdivisionGranularity.circle : 1;

for (const {feature, id, index, sourceLayerIndex} of features) {
const needGeometry = this.layers[0]._featureFilter.needGeometry;
const evaluationFeature = toEvaluationFeature(feature, needGeometry);
Expand Down Expand Up @@ -121,7 +135,7 @@ export class CircleBucket<Layer extends CircleStyleLayer | HeatmapStyleLayer> im
const {geometry, index, sourceLayerIndex} = bucketFeature;
const feature = features[index].feature;

this.addFeature(bucketFeature, geometry, index, canonical);
this.addFeature(bucketFeature, geometry, index, canonical, granularity);
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}
Expand Down Expand Up @@ -156,37 +170,63 @@ export class CircleBucket<Layer extends CircleStyleLayer | HeatmapStyleLayer> im
this.segments.destroy();
}

addFeature(feature: BucketFeature, geometry: Array<Array<Point>>, index: number, canonical: CanonicalTileID) {
addFeature(feature: BucketFeature, geometry: Array<Array<Point>>, index: number, canonical: CanonicalTileID, granularity: CircleGranularity = 1) {
// Since we store the circle's center in each vertex, we only have 3 bits for actual vertex position in each axis.
// Thus the valid range of positions is 0..7.
// This gives us 4 possible granularity settings that are symmetrical.

// This array stores vertex positions that should by used by the tessellated quad.
let extrudes: Array<number>;

switch (granularity) {
case 1:
extrudes = [0, 7];
break;
case 3:
extrudes = [0, 2, 5, 7];
break;
case 5:
extrudes = [0, 1, 3, 4, 6, 7];
break;
case 7:
extrudes = [0, 1, 2, 3, 4, 5, 6, 7];
break;
default:
throw new Error(`Invalid circle bucket granularity: ${granularity}; valid values are 1, 3, 5, 7.`);
}

const verticesPerAxis = extrudes.length;

for (const ring of geometry) {
for (const point of ring) {
const x = point.x;
const y = point.y;
const vx = point.x;
const vy = point.y;

// Do not include points that are outside the tile boundaries.
if (x < 0 || x >= EXTENT || y < 0 || y >= EXTENT) continue;

// this geometry will be of the Point type, and we'll derive
// two triangles from it.
//
// ┌─────────┐
// │ 3 2 │
// │ │
// │ 0 1 │
// └─────────┘

const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray, feature.sortKey);
const index = segment.vertexLength;
if (vx < 0 || vx >= EXTENT || vy < 0 || vy >= EXTENT) {
continue;
}

addCircleVertex(this.layoutVertexArray, x, y, -1, -1);
addCircleVertex(this.layoutVertexArray, x, y, 1, -1);
addCircleVertex(this.layoutVertexArray, x, y, 1, 1);
addCircleVertex(this.layoutVertexArray, x, y, -1, 1);

this.indexArray.emplaceBack(index, index + 1, index + 2);
this.indexArray.emplaceBack(index, index + 3, index + 2);
const segment = this.segments.prepareSegment(verticesPerAxis * verticesPerAxis, this.layoutVertexArray, this.indexArray, feature.sortKey);
const index = segment.vertexLength;

segment.vertexLength += 4;
segment.primitiveLength += 2;
for (let y = 0; y < verticesPerAxis; y++) {
for (let x = 0; x < verticesPerAxis; x++) {
addCircleVertex(this.layoutVertexArray, vx, vy, extrudes[x], extrudes[y]);
}
}

for (let y = 0; y < verticesPerAxis - 1; y++) {
for (let x = 0; x < verticesPerAxis - 1; x++) {
const lowerIndex = index + y * verticesPerAxis + x;
const upperIndex = index + (y + 1) * verticesPerAxis + x;
this.indexArray.emplaceBack(lowerIndex, upperIndex + 1, lowerIndex + 1);
this.indexArray.emplaceBack(lowerIndex, upperIndex, upperIndex + 1);
}
}

segment.vertexLength += verticesPerAxis * verticesPerAxis;
segment.primitiveLength += (verticesPerAxis - 1) * (verticesPerAxis - 1) * 2;
}
}

Expand Down
Loading

0 comments on commit a283af1

Please sign in to comment.