Dynamic hillshade with terrain doesn't update lighting smoothly
mapbox-gl-js version: 2.15.0
browser: Chrome
Description
In v2.15.0, when using dynamic hillshade with 3D terrain applied, lighting does not update smoothly. There is one edgecase where it does seem to update smoothly, as noted below.
When in 2D in this example https://docs.mapbox.com/mapbox-gl-js/example/hillshade/, the dynamic hillshade lighting updates smoothly.
In v3+, dynamic hillshade lighting with 3D terrain applied continues to not update smoothly, although the behavior is slightly different than this demo using v2.15.0.
Also worth noting is the mobile SDKs update lighting smoothly in the same scenarios.
Steps to Trigger Behavior
- Spin up code snippet below locally, note lighting rendering smoothly
- Comment out either of the noted lines
- Note lighting no longer renders smoothly
Demo Video: https://github.com/user-attachments/assets/f3f3c43a-e129-49cb-b805-cb1553eaed98
Note at first, the dynamic hillshade lighting updates smoothly. Once I comment other either of the two lines, it will start updating only once the camera has stopped and on mouseup.
Link to Demonstration
Doesn't seem to render correctly in jsbin, so pasting code here
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dynamic Hillshade</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = "pk.eyJ1IjoiZXhhbXBsZXMiLCJhIjoiY2p0MG01MXRqMW45cjQzb2R6b2ptc3J4MSJ9.zA2W0IkI0c6KaAhJfk9bWg"
function initializeMap(stylesheet) {
const demSource = {
maxzoom: 14,
type: "raster-dem",
url: "mapbox://mapbox.mapbox-terrain-dem-v1",
encoding: "mapbox",
tileSize: 512,
}
stylesheet.sources["dem"] = Object.assign({}, demSource)
stylesheet.sources["hillshadeDem"] = Object.assign({}, demSource)
stylesheet.terrain = { source: "dem" }
const hillshadeIdx = stylesheet.layers.findIndex((l) => l.id === "hillshade")
// Replace static hillshade layer with dynamic one
stylesheet.layers.splice(hillshadeIdx, 1, {
id: "hillshadeDem",
source: "hillshadeDem",
type: "hillshade",
})
const map = new mapboxgl.Map({
container: "map",
style: stylesheet,
center: [-106.28042, 39.74775],
zoom: 14.65,
bearing: 67,
pitch: 56,
hash: true,
// Comment this out
optimizeForTerrain: false,
})
map.once('load', () => {
// Comment this out
// Force a symbol layer near the bottom of the stylesheet.
// This is out of "intended render order" when in 3D, which triggers the edge case, resulting in
// the dynamic hillshade lighting updating smoothly.
map.moveLayer("contour-label", "contour-line")
})
}
fetch(`https://api.mapbox.com/styles/v1/mapbox/outdoors-v12?access_token=${mapboxgl.accessToken}`)
.then((res) => res.json())
.then(initializeMap)
.catch((err) => console.error(err))
</script>
</body>
</html>
Expected Behavior
In this example, dynamic hillshade lighting updates smoothly. I would expect it to work this way when 3D terrain is added to the map as well.
Actual Behavior
In v2.15, the hillshade only updates smoothly in 3D under a very specific scenario. Under all other scenarios, the lighting updates on camera stop and mouse up.
In v3+, the lighting behavior is slightly different, but still does not update smoothly.
Hi @matteiben-onx,
Could you please elaborate more on the expected behavior? Starting with v3.x, GL JS no longer supports the optimizeForTerrain map option. Layer rendering on the globe and terrain is always optimized now.
@stepankuzmin Sure thing
What I'd expect is shown in seconds 2 - 7 in this video https://github.com/user-attachments/assets/f3f3c43a-e129-49cb-b805-cb1553eaed98
Notice as the camera pans, the lighting updates smoothly. As pointed out above, the smoothly updating lighting is not the norm, even on v2.15.0. I had to get the map into a very specific scenario to result in the smooth lighting updates.
Using v3.4 (with optimizeForTerrain removed), the gif below shows a behavior where the lighting only updates once the camera has stopped and on mouseup.
Let me know if I can provide more details.
Hi Team Mapbox - appreciate the sync this afternoon. After reviewing our upcoming roadmap intentions, we would appreciate the MB team being able to prioritize looking at this since it's impactful to the customer experience of an upcoming release we are planning.
I ran the 3.7 beta-1 through my test document. The update seems to resolve the issue https://github.com/mapbox/mapbox-gl-js/releases/tag/v3.7.0-beta.1
@matteiben-onx Thank you for your reply! Good to hear. I'm closing the issue then