共计 3294 个字符,预计需要花费 9 分钟才能阅读完成。
技术背景
三维可视化在城市规划、应急管理和智慧园区等领域应用广泛。ArcGIS API for JavaScript 提供了强大的 WebGL 渲染能力,可直接在浏览器中呈现逼真的三维场景,而无需安装插件。通过将二维建筑轮廓拉伸为立体模型,我们能快速构建城市级三维景观。

数据准备
推荐使用 GeoJSON 作为建筑数据源,其优势在于:
- 纯文本格式,可直接用文本编辑器查看修改
- 主流 GIS 工具(如 QGIS)都支持导出
- 可通过 geojson.io 在线编辑验证
获取建筑数据通常有两种方式:
- 从开放数据平台下载(如各城市的地理信息公共服务平台)
- 使用 OSM 数据转换工具导出特定区域建筑轮廓
数据字段建议包含:
height建筑高度(单位:米)name建筑名称(可选)type建筑类型(如住宅 / 商业,用于分类着色)
核心实现
1. 场景初始化
首先创建基础三维场景,需要设置:
- 底图(推荐使用
arcgis-topographic矢量底图) - 初始视角(通过 Camera 定位到目标区域)
- 地形(如需真实地表起伏)
require(["esri/Map", "esri/views/SceneView"], (Map, SceneView) => {
const map = new Map({
basemap: "arcgis-topographic",
ground: "world-elevation" // 启用全球地形
});
const view = new SceneView({
container: "viewDiv",
map: map,
camera: { // 初始镜头位置
position: [120.1, 30.2, 2000], // 经度, 纬度, 海拔
tilt: 65, // 倾斜角度
heading: 0 // 朝向
}
});
});
2. 建筑数据加载
使用 GeoJSONLayer 加载建筑数据,注意:
- 需通过
renderer指定 3D 拉伸方式 - 字段映射将 GeoJSON 属性对应到可视化参数
const buildingsLayer = new GeoJSONLayer({
url: "./data/buildings.geojson",
renderer: {
type: "simple",
symbol: {
type: "polygon-3d",
symbolLayers: [{
type: "extrude",
size: 5, // 默认高度(会被字段覆盖)material: {color: "#CCCCCC"}
}]
},
visualVariables: [{
type: "size",
field: "height", // 使用 height 字段控制高度
stops: [{value: 0, size: 0}, {value: 100, size: 100}]
}]
}
});
map.add(buildingsLayer);
3. 样式配置
通过 visualVariables 实现分类着色:
// 在 renderer 中添加颜色视觉变量
visualVariables: [
{
type: "color",
field: "type",
stops: [{ value: "residential", color: "#FFD966"},
{value: "commercial", color: "#EA7A7A"}
]
}
]
4. 交互功能
添加点击查询显示建筑信息:
view.on("click", (event) => {view.hitTest(event).then((response) => {if (response.results.length) {const graphic = response.results[0].graphic;
console.log("选中建筑:", graphic.attributes);
}
});
});
完整代码示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>3D 建筑可视化 </title>
<link rel="stylesheet" href="https://js.arcgis.com/4.25/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.25/"></script>
<style>
#viewDiv {height: 100vh; width: 100%;}
</style>
</head>
<body>
<div id="viewDiv"></div>
<script>
require([
"esri/Map",
"esri/views/SceneView",
"esri/layers/GeoJSONLayer"
], (Map, SceneView, GeoJSONLayer) => {
// 初始化地图
const map = new Map({
basemap: "arcgis-topographic",
ground: "world-elevation"
});
// 创建三维视图
const view = new SceneView({
container: "viewDiv",
map: map,
camera: {position: [120.1, 30.2, 2000],
tilt: 65,
heading: 0
}
});
// 加载建筑数据
const buildingsLayer = new GeoJSONLayer({
url: "buildings.geojson",
renderer: {
type: "simple",
symbol: {
type: "polygon-3d",
symbolLayers: [{
type: "extrude",
size: 5,
material: {color: "#CCCCCC"}
}]
},
visualVariables: [
{
type: "size",
field: "height",
stops: [{value: 0, size: 0}, {value: 100, size: 100}]
},
{
type: "color",
field: "type",
stops: [{ value: "residential", color: "#FFD966"},
{value: "commercial", color: "#EA7A7A"}
]
}
]
}
});
map.add(buildingsLayer);
// 点击交互
view.on("click", (event) => {view.hitTest(event).then((response) => {if (response.results.length) {const graphic = response.results[0].graphic;
console.log("建筑信息:", graphic.attributes);
}
});
});
});
</script>
</body>
</html>
性能优化
当建筑数量超过 5000 时,建议采用以下策略:
- 数据分级:
- 按缩放级别加载不同 LOD 数据
-
使用
FeatureReductionCluster聚合显示远处建筑 -
渲染优化:
- 开启
featureReduction减少渲染要素 -
使用
tileMode: true启用矢量切片 -
内存管理:
- 对不可见区域调用
layer.when()延迟加载 - 移除超出视野范围的图层
常见问题
- 建筑不显示:
- 检查 GeoJSON 坐标系是否为 WGS84(EPSG:4326)
-
确认 height 字段值不为 null
-
颜色未生效:
- 验证 type 字段值与 stops 中的 value 完全匹配(包括大小写)
-
检查 visualVariables 是否放在 renderer 内
-
性能卡顿:
- 使用
view.watch('stationary')只在镜头静止时加载数据 - 通过
layer.visible = false暂时隐藏复杂图层
扩展思考
可尝试添加以下功能提升体验:
- 日夜切换 :通过
environment.lighting修改太阳位置 - 阴影效果:启用
view.environment.shadows = true - 动画飞入 :使用
goTo()实现镜头穿梭效果 - 属性查询:结合 PopupTemplate 显示详细建筑信息
通过本文的实践,我们完成了从数据准备到三维展示的完整流程。接下来可以尝试整合实时数据(如交通流量)或接入 IoT 设备信息,构建更丰富的三维应用场景。
正文完
发表至: GIS开发
近一天内
