-
Notifications
You must be signed in to change notification settings - Fork 59
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
Add a hillshade layer #1157
base: main
Are you sure you want to change the base?
Add a hillshade layer #1157
Conversation
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.
This is a beautiful starting point. I shared some screenshots with the AARoads Wiki folks and the reception has been quite positive.
src/layer/index.js
Outdated
@@ -83,6 +84,8 @@ export function build(locales) { | |||
|
|||
lyrFerry.ferry, | |||
|
|||
lyrHillshade.hillshading, |
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.
The Terrarium tiles are a bit sensitive to artificial structures like dams that look a bit strange over water, like the Lock and Dam Number 12 on the Mississippi River at Bellevue, Iowa:
If we move this layer lower in the stack, such as right below water_line
, then the waterbody layer would tend to obscure this and other anomalies over water:
However, the tradeoff is that the “hill” shading would no longer double as a bathymetry layer at sea:
Before | After |
---|---|
While bathymetry is pretty cool, I think it’s far enough out of scope of a (land) transportation map as to be a distraction. It also looks a bit discolored without hypsometric tinting, whereas on land the absence of that tinting is quite reasonable on a non-topographic map. (General-purpose overview maps would prioritize showing the continental shelf using hypsometric tinting before bothering with elevation shading.)
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.
Unfortunately this means farewell to "tunnels under terrain", which was pretty cute.
It's a little odd to see the ocean floor load and then get covered with water but it makes sense when you think about it.
Now there are no longer enormous glitches all over the entire ocean, just a few.
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.
Incidentally, #995 gives tunnels a different treatment that wouldn’t really exhibit the cute underlapping effect anyways.
The flash of bathymetry feels like an unsubtle Easter egg, of which we have too few in this project. 🙃 In seriousness, maybe we could load the DEM source and hillshade layer only after the main sources and layers load, to avoid jank and unnecessary bandwidth and power usage. To avoid distracting the user on land, we could fade in the hillshade layer with a hillshade-exaggeration-transition
property, akin to deferred 3D terrain in F4Map, though I don’t know how well that would perform.
src/layer/hillshade.js
Outdated
"hillshade-shadow-color": "rgba(102,85,51,1)", | ||
"hillshade-highlight-color": "rgba(255,255,204,1)", | ||
"hillshade-accent-color": "rgba(0,0,0,1)", |
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.
With these colors, some road lines don’t have a lot of contrast against the background, while the knockouts around labels stand out enough to look like halos again. Maybe we could try moving all three colors closer to the preexisting background color. This could also help the layer recede into the background while still conveying information about rugged terrain to those who look for it.
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.
Tamed it a lot. Since the hillshade is now restricted to the luminance space, I increase the exaggeration at low zooms since it no longer fights with other colors. It fades away at high zooms to avoid ruining the foreground by being a murky blob, and to avoid getting confused by things like stadiums.
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.
In the flat lands, the old version made it actually look like a crumpled paper map :-D
src/js/icon_control.js
Outdated
} | ||
|
||
_onClick = () => { | ||
if (this._map.getLayoutProperty(this._layerId, "visibility") == "none") { |
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.
Astonishingly, my iPhone 8 is able to keep up with the map with the hillshading enabled, but it turns the battery meter into a sad trombone. Should we hide the layer by default on mobile devices, or somehow detect less powerful devices?
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 upgraded maplibre-gl, the changelog mentions some performance improvements, want to try 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.
The first render is reasonably quick, but there’s a lot more stuttering while panning than on main. The battery goes down by a few percent after about 20 seconds of panning around the Appalachians at zoom level 8. That’s still much better than the majority of ad-laden news websites these days, but the stuttering is a bummer.
It still avoids strong artifacts and maplibre-gl 4 is using much less memory. Reduce maximum hillshade-exaggeration from 1 to 0.5. The default is 0.5; going higher throws away contrast.
The OSM US Tileservice now has pre-rendered hillside and contour lines available (thanks @jake-low!) Using these would significantly improve client-side performance. If the hillshade parameter aren't to your liking then we can consider rendering another set.
|
There’s some discussion about both approaches in #780. Dynamic hillshading with a |
The prerendered tiles are a lot harder to wrangle the desired look out of. Ideally we want to blend it with the beige background color, solid fills like aerodrome, park, and the fat purple boundary casing. (Or at least, that's what happened immediately when I slotted the dynamic hillshade on top of those layers, and I like it.) As a workaround, I tried to make the background color very dark and saturated and put the hillshade jpg with 96% alpha -- this doesn't look great, and the aggressive background shows through when the hillshade tiles aren't loaded. Another way to make it work is to change all those background layers to be alpha blended on top of the hillshade. Might work but the colors would all end up a bit murky; they're currently fully opaque and paint on top of each other. Just spitballing, what if the hillshade tiles were instead solid black with alpha channel, so that they can blend with a background color more easily. Or perhaps some color instead of black, so that the raster-* layer properties can be used. (Either webp or png?) (It would be very nice if maplibre supported a color matrix or blend modes to be able to do this, but that's far away.) |
If performance is the only concern, I’d favor merging this feature as is, but disabled by default (again, maybe only for certain user agents). Then we could figure out how to make it more performant or provide alternatives before enabling it by default. |
Oops I didn't mean to click the ready for review button. Maybe that's ok though? Anyway feel free to change it back if not... |
Overall, I'm really liking the look of Americana with hill shading. It does diverge from the paper highway map aesthetic, but I've always felt that some level of hill shading would help fill in the empty spaces. It's just a matter of balancing the shading so it's not too overpowering, but still visible enough. This style isn't an outdoors focused topo map after all.
Here's a comparison of the same spot with this PR and in OpenTrailMap which uses the raster hillshade tiles @quincylvania mentioned. Location: PR preview, OpenTrailMap.
Subjectively, the OpenTrailMap hillshading is a bit more pleasing to my eye. I'm not entirely sure why this is. Maybe uni-directional vs multi-directional lighting? On the other hand, the OpenTrailMap shading does look a bit strange when the map is rotated 180 degrees. It is quite a cool how the dynamic lighting implemented in this PR causes the hillshading to change as the map is rotated.
Unless a map has 3D terrain and buildings1 I find map rotation and tilting to be more of a fun gimmick than a useful feature. I mostly trigger it by accident when using a two finger pinch to zoom on a touch screen and the gesture gets interpreted as a slight rotation or tilt as well. I'd be fine with rotate and tilt being disabled. Footnotes
|
Actually, there’s quite a bit of precedent for road maps out west to include subtle hillshading. Aside from filling in blank space, it communicates to the motorist whether they’ve got a climb or potentially some challenging winter road conditions ahead of them. What’s new is the modicum of hillshading in flatter regions, where paper maps tend not to bother. But for us, it’s all one map.
I assume it has more to do with us fidgeting with the exaggeration, color, and maximum zoom level (which affects the resolution). |
I darkened the shadow color somewhat, and it's a closer match to the OpenTrailMap screenshot. I think I was trying to avoid broadly darkening the existing background color, but it's probably fine. It's no darker than buildings right now. (Some labels are already difficult to read and this change doesn't make it worse.) |
be88f28
to
021c041
Compare
There are definitely some bad artifacts in this DEM. In the US it seems mostly pretty okay, but in other parts of the world it can be a bit janky. Area of the Alps for example: location: https://preview.ourmap.us/pr/1157/#map=12.14/46.78211/8.62852 |
@jleedev: seems like you have a good grasp already of the limitations of prerendered hillshade tiles, but I just wanted to reply with some details about what I did for OpenTrailMap in case it's useful to you. As you mentioned, there are basically two ways MapLibre can be used to blend a prerendered hillshade tileset with another style layer like a fill layer: either you put the hillshade on top, or you put the fill layer on top. Both have drawbacks. If the hillshade is on top, it washes out the colors (reduces the saturation) of the fill layer. If the fill layer is on top, it reduces the contrast of the hillshading. You can try to compensate against either effect, by increasing the base saturation of the fill layer style, or the base contrast of the hillshade rasters, respectively. But if the fill layer doesn't cover the whole planet (i.e. there are areas of the map that aren't covered by a polygon in the layer source), then you'll see boundaries in the rendered map where either the saturation of the fill layer or the contrast of the hillshade changes undesirably, depending on which choice you make. Another factor that might influence this choice is how MapLibre handles opacity blending. When you set a fill layer to 50% opacity, it blends each feature in the layer at that opacity, so areas where features overlap will have a higher total opacity. This may or may not be desired. What I've personally found to work pretty well, and what I did for the hillshading I worked on for OpenTrailMap, is to set the hillshade layer above the I find this the nicest approach from a cartography perspective because you still have direct control over the colors of all the layers placed underneath the hillshade (and don't have to worry about how they'll blend with each other, which can lead to a "muddy" effect as you mentioned). And the hillshade raster that's overlaid on top has a predictable effect on the colors below: it desaturates them by a factor that's roughly proportional to the opacity of the hillshade. That predictability makes the effect easier to correct for when picking colors.
That's an interesting idea. PNG would probably not be a good choice, since it would dramatically increase the size of the tileset (hillshading has lots of high frequency detail that compresses really well as JPEG). WebP might work, though I haven't tested whether MapLibre supports alpha channels in WebP images. You'd still have to deal with the same tradeoff described above, but only in areas with lots of relief - flat areas would be mostly transparent. I don't have an intuitive idea of whether this would look pleasant or not, but it could be interesting to explore that approach. |
Really the purpose is to avoid filling the screen with dark gray when overzooming on a hill (and instead to fill the screen with a nice beige).
What's going on here:
TODO here:
Future work:
Fixes #780