Repository navigation
Replies: 4 comments 1 reply
|
The deleted example never really displayed shadows on a 3D terrain. It created a flat plane in the three.js scene, and added some lighting so that the shadows fall on that flat plane. Since the style used did not load a 3d terrain, things looked ok. But it would look bad with an actual 3D terrain. This trick works in the newer example. If you don't need a 3D terrain in maplibre, simply add a three.js plane with some directional light, as you would normally create shadows in Three.js. A proper shadow which follows 3D terrain is doable but not trivial. Three.js currently does not automatically have access to the maplibre terrain and maplibre-gl-three (the library used in the replacement example) does not provide a helper function to do this. (By the way this separation of data is mentioned in features & limitations) The simplest way to do it might be deriving a Three.js geometry based on the same terrain tiles which the maplibre map uses, and casting the shadow on those. This might even be easier with qmesh than it is with a raster terrain, since qmesh is already vectorized. There could be some more sophisticated/performant lower level implementations that couples the two libraries tighter and somehow extracts the 3d terrain from the guts of maplibre, but I would need to investigate further and off the top of my head this sounds pretty complicated. I am maintaining maplibre-gl-three in my spare time and some geometry-generating helper function could be something I would do when I have the time and motivation, but it's not high priority for me right now. (If someone is willing to fund this work let me know). |
|
Something that is very much worth mentioning: If you are using 3D Tiles along with a 3D model, you should be able to cast shadows on the 3D Tiles, since both the 3D tiles and the 3D model are three.js geometries. The ground of a good quality 3D tiles should closely follow the MapLibre terrain, so I think this would give the impression of a shadow casted on MapLibre too. I have not tested this and maybe I will. If your 3D Tiles model includes buildings with proper height, this somewhat resolves extrusion shadow casting too. |
|
Short version: there is nothing built in. MapLibre has no shadow casting at all. The root Since 6.13.0 there is an experimental custom layer API that makes this practical without copying the terrain into three.js:
const shadowLayer = {
id: 'terrain-shadows',
type: 'custom',
terrainTileRevision: 0,
onAdd(map, gl) { /* programs, shadow depth FBO, RGBA32F height map (needs EXT_color_buffer_float) */ },
prerender(gl, options) {
options.renderTerrainHeightMap?.({texture: this.heightMap, width: 512, height: 512, bounds});
this.renderShadowDepth(gl); // your occluders, rendered with the sun's view/projection
},
render() {}, // used only when terrain is off
renderToTerrainTile(gl, {tileID}) {
// full tile quad; fragment shader: mercator xy -> sample height map -> light space -> depth test
// fragColor = vec4(0.0, 0.0, 0.0, 0.35) where shadowed, otherwise discard
}
};
map.addLayer(shadowLayer, firstSymbolLayerId);The add-custom-layers-that-follow-the-terrain example has working code for both hooks: the tile-to-Mercator math in Caveats:
|
Uh oh!
There was an error while loading. Please reload this page.
There used to be an example of adding a 3d model with shadow using threejs. Now it has been removed.
Is there a way to display shadows of all 3D objects, including extrusions and added models (e.g., trees, bridges, vehicles, etc.), on 3D terrain?
All reactions