-
-
Notifications
You must be signed in to change notification settings - Fork 754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Heatmap Fix for 3D terrain #4571
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4571 +/- ##
==========================================
- Coverage 87.90% 87.88% -0.02%
==========================================
Files 247 247
Lines 33504 33574 +70
Branches 2373 2366 -7
==========================================
+ Hits 29453 29508 +55
- Misses 3078 3098 +20
+ Partials 973 968 -5 ☔ View full report in Codecov by Sentry. |
Thanks for taking the time to solve this! |
What about releasing the buffers when the tiles are not needed any more (i.e. move the map around and zoom in and out to load more tiles)? |
@prozessor13 @kubapelc please let me know what you think of this PR, and also how it works affect the globe branch. |
Hi, this looks really nice! However I have some performance concerns.
I think your approach is ideal for fixing the heatmaps-on-terrain bug, but I'm really concerned that this can be a performance regression for non-terrain maps. By my intuition, it should be slower than the old approach: The per-tile textures you allocate are really large, typical Contrast this with the old approach of rendering heatmaps: A single framebuffer is used, which is 1/4 the size of the screen in each axis. This is just 960x540 for a 4K screen, roughly the same amount of pixels as 2 tiles of 512x512. We only pay the overhead of switching framebuffers once per frame. I suggest these improvements:
|
src/render/draw_heatmap.ts
Outdated
|
||
let fbo = tile.fbo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't tile.fbo
used for terrain's render-to-texture? How does this interact with what you draw into the tiles during heatmap rendering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I replicated the approach of how the hillshade works. This is where it came from!
/~https://github.com/maplibre/maplibre-gl-js/blob/main/src/render/draw_hillshade.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why this works. Maybe @prozessor13 can clarify? Also shouldn't heatmaps use more that 8 bit precision for blending the kernel intensities?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, heatmap uses context.HALF_FLOAT
which a 16-bit precision floating-point format whenever it is there. I removed gl.UNISIGNED_BYTE
because as the performance was increasing I thought providing higher precision texture would be better but that was a mistake because after testing on the old Android device I explored a bit and found out that old Android devices don’t provide support for float in fragment shaders. I think that was the reason it was added before in the first place.
I think I should add gl.UNISIGNED_BYTE
again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like current heatmap code checks whether 16 bit floats are supported and only uses them if they are, I think that is a good approach.
I also checked the render-to-texture and terrain code again, and I was wrong, tile.fbo
is not used by terrain at all. But it is used by hillshade. What if you enable both heatmaps and hillshade?
If I understand your changes, both layers now use the same framebuffer object, both attach a texture to in (into the same attachment slot) and both could draw different things into the fbo, which could collide.
If that is really the case, I suggest using a different fbo for heatmaps. But I'm not sure how to best manage them, current tile.fbo
seems to be deleted in raster_dem_tile_source.ts
, so it is very much tied to hillshade.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if to use HashMap in layer.heatmapFbo
? It will access the fbo based on the tilekey
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that sound like a good place!
As for globe integration, if this approach is only used for terrain in the end, then no additional work would be needed since globe doesn't support terrain (yet). Otherwise, adapting this to render on a sphere should be easy, but making sure that kernel sizes are consistent across latitudes on a globe would probably take a few hours. |
Hmm.. yeah it maybe broken but I am not sure of it..
This is running on Nexus One: bandicam.2024-08-17.18-48-01-830.mp4bandicam.2024-08-17.18-49-42-459.mp4OLD APPROACH: bandicam.2024-08-17.19-18-22-807.mp4both of the approach gives white screen of death when refresh:
Then why use it for the terrain also if it does not benefit much?
Seems interesting.. we can work on a new PR to implement this method. |
I missed a key fact about your approach, that when it is used alongside terrain, each tile will get rendered only when terrain prerenders a given tile to texture, and that terrain will then cache the finished colormap for the tile. So no rendering work needs to be done after this point. This would indeed make your approach very performant! I'm still not sure how this would behave when terrain is disabled, and still think it might be best to use the old approach for that case, since it is performant and flexible, handling dynamic changes. I think you can disregard my other comments about lowering texture size and only redrawing when something changes, although it would probably be a good idea to see how this behaves with dynamic heatmaps, such as the example heatmap, which changes kernel intensity depending on zoom level. EDIT: your example already has dynamic kernel sizes, and it works well there.
I think you approach is the best way to make heatmaps follow the terrain mesh. Alternative would be use the old approach and draw kernels with a mesh that would sample the heightmap and use Z-testing, which would probably not work very well at tile borders and produce artifact, since the heatmap FBO is so much smaller than the screen. EDIT: maybe heatmaps should be added to the |
heatmap-color not working in demo |
I am unable to reproduce this. Can you provide with the reproduction steps? heatmap.mp4 |
Thank you for the insightful review and feedback, @kubapelc! Your comments have been very helpful in understanding the implications of this approach, especially regarding terrain integration. Also should we implement texture altas? I think it will benefit the heatmap as it can reduce the overhead but it would be difficult to implement as I have not worked with it before. I will need quite a good amount of time for it. |
I think you can skip the texture atlas thing, it really would be difficult to implement and also has some drawbacks. I think it should not be needed, terrain already uses a single texture per tile instead of atlasing and it seems to be fine. |
Sorry for lack of information. I mean the heatmap color doesn't change when i modify the heatmap-color option |
Maybe can you compare between the old approach and new approach to get the difference? |
I like the separation to different flows, it makes the previous code that worked being not affected, which is great. |
Is the build size ok? |
Yes, please increase the build size. |
I think the build size is not needed to change now. |
The code looks good, The original issue |
I have not got problem as such for now. |
THANKS!! |
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [maplibre-gl](https://maplibre.org/) ([source](/~https://github.com/maplibre/maplibre-gl-js)) | dependencies | minor | [`4.5.2` -> `4.7.0`](https://renovatebot.com/diffs/npm/maplibre-gl/4.5.2/4.7.0) | --- ### Release Notes <details> <summary>maplibre/maplibre-gl-js (maplibre-gl)</summary> ### [`v4.7.0`](/~https://github.com/maplibre/maplibre-gl-js/blob/HEAD/CHANGELOG.md#470) [Compare Source](maplibre/maplibre-gl-js@v4.6.0...v4.7.0) ##### ✨ Features and improvements - Support multiple layers in `map.on`, `map.once` and `map.off` methods ([#​4570](maplibre/maplibre-gl-js#4570)) - Ensure GeoJSON cluster sources emit a console warning if `maxzoom` is less than or equal to `clusterMaxZoom` since in this case you may see unexpected results. ([#​4604](maplibre/maplibre-gl-js#4604)) ##### 🐞 Bug fixes - Heatmap Fix for 3D terrain ([#​4571](maplibre/maplibre-gl-js#4571)) - Fix Map#off to not remove listener with layer(s) registered with Map#once ([#​4592](maplibre/maplibre-gl-js#4592)) - Improve types a bit for `addSource` and `getSource` ([#​4616](maplibre/maplibre-gl-js#4616)) - Fix the color near the horizon when terrain is enabled without any sky ([#​4607](maplibre/maplibre-gl-js#4607)) - Fix bug where `fitBounds` and `cameraForBounds` would not display across the 180th meridian (antimeridian) - Fix white flickering on map resize ([#​4158](maplibre/maplibre-gl-js#4158)) - Fixed a performance regression related to symbol placement ([#​4599](maplibre/maplibre-gl-js#4599)) - Fix a bug where cloning a Transform instance didn't include the `lngRange`. This caused a bug where using `transformCameraUpdate` caused the `maxBounds` to stop working just for east/west bounds. ([#​4625](maplibre/maplibre-gl-js#4625)) ### [`v4.6.0`](/~https://github.com/maplibre/maplibre-gl-js/blob/HEAD/CHANGELOG.md#460) [Compare Source](maplibre/maplibre-gl-js@v4.5.2...v4.6.0) ##### ✨ Features and improvements - Prefer local glyph rendering for all CJKV characters, not just those in the CJK Unified Ideographs, Hiragana, Katakana, and Hangul Syllables blocks. ([#​4560](maplibre/maplibre-gl-js#4560))) ##### 🐞 Bug fixes - Fix right-to-left layout of labels that contain characters in the Arabic Extended-B code block. ([#​4536](maplibre/maplibre-gl-js#4536)) - Fix 3D map freezing when camera is adjusted against map bounds. ([#​4537](maplibre/maplibre-gl-js#4537)) - Fix `getStyle()` to return a clone so the object cannot be internally changed ([#​4488](maplibre/maplibre-gl-js#4488)) - Fix issues with setting sky to `undefined` ([#​4587](maplibre/maplibre-gl-js#4587))) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](/~https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC40Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguODYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiZGVwZW5kZW5jaWVzIl19--> Reviewed-on: https://git.tristess.app/alexandresoro/ouca/pulls/52 Reviewed-by: Alexandre Soro <code@soro.dev> Co-authored-by: renovate <renovate@git.tristess.app> Co-committed-by: renovate <renovate@git.tristess.app>
@Samarth1696 @kubapelc Can you help me merge this code to the globe branch? |
I'll take a look at it! |
Fixes: #1081
There are 2 changes I have done in this PR:
Heatmap can now use Terrain data to get elevation, which fixes the floating heatmap issue.
Replaced the large single framebuffer implementation to per-tile framebuffer approach, where now each tile have its own framebuffer.
Before:
https://stackblitz.com/edit/web-platform-tqhkxm
After:
https://stackblitz.com/edit/stackblitz-starters-zmwkdx?file=index.html
The heatmap was already split into tiles, so I just had to change the implementation of the framebuffer and splitted the heatmap texture into tiles. And that worked well!!
This is the performance improvement that I got:
But I am not sure if the failing tests are acceptable and I was already expecting the heatmap render tests to fail... If you feel that we should not go with this implementation, then let me know so that I will create a new PR with just the floating heatmap fix!
Also that 4 tile tests in render tests were failing even before I started working on the issue.
Launch Checklist
CHANGELOG.md
under the## main
section.