基于Mapbox GL 3D实现本地建筑阴影投影的技术咨询
本地实现Mapbox GL 3D建筑太阳阴影投影方案
核心思路
通过两个独立图层实现真实阴影效果:
- 建筑本体层:用
fill-extrusion渲染3D建筑实体 - 阴影层:用支持模糊的
fill图层,基于太阳角度为每个建筑计算专属投影偏移,替代简单的图层整体平移
步骤1:用SunCalc计算太阳参数
先获取目标时间的太阳高度角(altitude)和方位角(azimuth):
altitude为正代表太阳在地平线上方,<=0时无阴影azimuth是从正北顺时针的弧度值,需转换为地图坐标系的偏移分量
核心计算公式:
// 建筑高度需和Mapbox坐标单位匹配(如米) const shadowLength = height / Math.tan(altitude); // 分解为东(x)、北(y)方向偏移 const xOffset = shadowLength * Math.sin(azimuth); const yOffset = -shadowLength * Math.cos(azimuth);
步骤2:实现真实阴影投影
不用图层整体平移,而是给阴影层设置数据驱动的平移表达式,让每个建筑根据自身高度计算偏移:
- 新增
fill类型阴影图层,与建筑本体层共享数据源 - 配置
paint属性:fill-color:半透明灰色(如rgba(0,0,0,0.2))fill-blur:设置模糊半径(如5,数值越大模糊效果越强)
- 用表达式实现动态偏移,避免太阳高度极低时偏移量异常:
// 假设数据源中建筑高度字段为'height' 'fill-translate': [ ['case', ['>', altitude, 0.1], // 太阳高度高于约5.7度时显示阴影 ['*', ['get', 'height'], Math.sin(azimuth) / Math.tan(altitude)], 0 ], ['case', ['>', altitude, 0.1], ['*', ['get', 'height'], -Math.cos(azimuth) / Math.tan(altitude)], 0 ] ]
步骤3:优化阴影效果
- 图层层级:阴影层置于建筑本体层下方(先添加阴影层,再添加建筑层)
- 增强模糊:若单图层模糊不足,可叠加2-3个阴影层,每层偏移量微增、透明度递减,模拟自然软阴影
- 无阴影处理:太阳高度<=0时,设置阴影层
visibility: 'none'
代码示例片段
// 1. 获取太阳参数(示例:当前时间,北京坐标) const date = new Date(); const lat = 39.9042; const lon = 116.4074; const sunPos = SunCalc.getPosition(date, lat, lon); const { altitude, azimuth } = sunPos; // 2. 添加阴影层 map.addLayer({ id: 'building-shadow', type: 'fill', source: 'buildings', // 与建筑层同源 paint: { 'fill-color': 'rgba(0, 0, 0, 0.2)', 'fill-blur': 5, 'fill-translate': [ ['case', ['>', altitude, 0.1], ['*', ['get', 'height'], Math.sin(azimuth) / Math.tan(altitude)], 0], ['case', ['>', altitude, 0.1], ['*', ['get', 'height'], -Math.cos(azimuth) / Math.tan(altitude)], 0] ] }, layout: { visibility: altitude > 0 ? 'visible' : 'none' } }); // 3. 添加建筑本体层 map.addLayer({ id: 'building-3d', type: 'fill-extrusion', source: 'buildings', paint: { 'fill-extrusion-color': '#aaa', 'fill-extrusion-height': ['get', 'height'], 'fill-extrusion-base': ['get', 'base_height'], 'fill-extrusion-opacity': 0.8 } });
关键注意事项
- 单位匹配:确保建筑高度单位(如米)与Mapbox Web墨卡托坐标单位一致,偏差过大需添加缩放系数
- 性能优化:建筑数量极多时,可提前在数据源中预计算阴影偏移量,减少实时表达式计算损耗
- 方向准确性:Mapbox的
fill-translate中x为东向递增、y为北向递增,因此y偏移需取负(太阳在北时阴影向南)
内容的提问来源于stack exchange,提问作者Federico González Brizzio
相关产品推荐
相关产品推荐

