3D 城市

具有水体要素图层(具有水反射)的场景和具有来自场景服务的数据的场景图层

什么是 3D 城市?

3D 城市可视化是对城市基础设施的逼真或抽象描述。在许多其他可视化中,此类可视化可以显示城市内的建筑物、交通基础设施、旅游景点或计划项目。

您可以使用从逼真到抽象的样式创建 3D 城市可视化。逼真的可视化以模仿现实的方式渲染城市;更抽象的样式使用逻辑示意图对象渲染建筑物、植被和其他城市元素。您还可以创建混合这些内容的可视化效果。

如何可视化 3D 城市

建筑物是大多数 3D 城市可视化的重要组成部分。可视化建筑物的最简单方法是在地形上显示其覆盖区。覆盖区将存储为面要素图层,并使用填充符号显示。当建筑物不是可视化的中心点,但您希望将其包含在上下文中时,此可视化类型非常有用。

建筑物覆盖区包含有关其高度的信息。您可以使用该高度数据来拉伸其多边形。这对于显示城市中建筑物的高度非常有用,即使建筑物的细节形状对于可视化并不重要。

当某些可视化显示建筑物的详细 3D 模型时,可以使其更具吸引力。3D 对象场景图层存储可使用纹理或颜色显示的大型城市模型。这些数据可以在 GeoScene Pro 或 CityEngine 等软件中建模,可以从 LiDAR 数据中提取,并且一些 3D 数据已在开放数据门户上提供。可视化此类数据的第一步是发布场景服务,将其作为场景图层添加到地图,然后在场景视图中可视化它。您可以使用原始纹理显示数据,也可以设置渲染器以显示具有不同颜色或数据驱动型样式的建筑物。

要以逼真 3D 方式可视化城市,您需要 3D 数据。最常见的数据图层类型是集成格网图层 带纹理的 3D 对象场景图层

3D 格网数据捕获是一个自动化过程,可基于大量重叠影像构建 3D 对象。此过程是使用无人机实现的,结果是一个包含城市中所有 3D 对象的纹理格网,例如建筑物、树木、道路和高程信息。通常,集成格网图层没有可用的样式选项,但可以将数据添加到场景中以标记项目,例如城市内的兴趣点、社区或地标。

示例

将建筑物可视化为覆盖区

在 3D 场景中,您并不总是需要使用 3D 数据来可视化建筑物。以下示例将建筑物覆盖区显示为面填充符号和拉伸面符号。数据由旧金山开放数据门户提供。要创建此可视化,请执行以下操作:

  1. 在 GeoScene Online 上下载数据并发布为要素图层。
  2. 创建要素图层并使用填充符号或拉伸面符号设置渲染器。
  3. 将图层添加到地图并在场景视图上设置地图。
                                                                                                                                         
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>
      Cities in 3D
    </title>
    <link rel="stylesheet" href="https://js.geoscene.cn/4.23/geoscene/themes/light/main.css" />
    <script src="https://js.geoscene.cn/4.23/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      .buttons {
        position: absolute;
        bottom: 20px;
        left: 0;
        right: 0;
        text-align: center;
      .geoscene-button {
        display: inline;
        background-color: white;
        min-width: 200px;
        max-width: 300px;
    </style>

    <script>
      require([
  "geoscene/config",
  "geoscene/Map",
  "geoscene/views/SceneView",
  "geoscene/layers/SceneLayer",
  "geoscene/layers/FeatureLayer"
], function (geosceneConfig,Map, SceneView, SceneLayer, FeatureLayer) {
  geosceneConfig.apiKey = "YOUR_API_KEY";
  const footprintBuildings = new FeatureLayer({
    url:
      "https://services2.arcgis.com/cFEFS0EWrhfDeVw9/arcgis/rest/services/san_francisco_footprints_selection/FeatureServer",
    renderer: {
      type: "simple",
      symbol: {
        type: "polygon-3d",
        symbolLayers: [
          {
            type: "fill",
            material: { color: [255, 237, 204] },
            outline: { color: [133, 108, 62, 0.5] }
          }
        ]
      }
    },
    visible: false
  });

  const extrudedBuildings = new FeatureLayer({
    url:
      "https://services2.arcgis.com/cFEFS0EWrhfDeVw9/arcgis/rest/services/san_francisco_footprints_selection/FeatureServer",
    renderer: {
      type: "simple",
      symbol: {
        type: "polygon-3d",
        symbolLayers: [
          {
            type: "extrude",
            material: { color: [255, 237, 204] },
            edges: {
              type: "solid",
              color: [133, 108, 62, 0.5],
              size: 1
            }
          }
        ]
      },
      visualVariables: [
        {
          type: "size",
          field: "heightcm",
          valueUnit: "centimeters"
        }
      ]
    visible: true
  // 创建地图
  var map = new Map({
    basemap: "geoscene-light-gray",
    ground: "world-elevation",
    layers: [footprintBuildings, extrudedBuildings]
  // 创建 SceneView
  var view = new SceneView({
    container: "viewDiv",
    map: map,
    camera: {
      position: [-122.39899666, 37.77940678, 314.88439],
      heading: 356.82,
      tilt: 78.61
    qualityProfile: "high"
  let type = "cartographic";
  document.getElementById("footprint").addEventListener("click", function (event) {
    footprintBuildings.visible = true;
    extrudedBuildings.visible = false;
  document.getElementById("extruded").addEventListener("click", function (event) {
    footprintBuildings.visible = false;
    extrudedBuildings.visible = true;
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div class="buttons">
      <button id="footprint" class="esri-button esri-button--secondary esri-button--half">Footprints</button>
      <button id="extruded" class="esri-button esri-button--secondary esri-button--half">Extruded footprints</button>
    </div>
  </body>
</html>

将建筑物可视化为 3D 对象

3D 几何是将建筑物可视化为其实际 3D 形状所必需的。存储此类数据的最佳方法是通过 3D 对象场景图层。在此图层中,每个建筑物都表示一个要素,该要素存储有关其几何、纹理以及一些属性详细信息(可选,例如建造年份或建筑物的使用情况)的信息。

在以下示例中,旧金山的建筑物将作为 3D 对象场景图层 添加到地图中。此图层包含每个建筑物的几何和纹理。

要使用其原始纹理显示建筑物,您需要在不使用渲染器的情况下将其添加到地图中。要移除该纹理并使用特定颜色显示建筑物,请应用包含具有所需颜色的格网符号的简单渲染器。如果图层还包含建筑物使用情况等属性,则可以应用生成数据驱动型可视化的渲染器。有关数据驱动型可视化的示例,请参阅 3D 中的分类数据

GeoScene JS API
                                                                                                                                  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>
      Cities in 3D
    </title>
    <link rel="stylesheet" href="https://js.geoscene.cn/4.23/geoscene/themes/light/main.css" />
    <script src="https://js.geoscene.cn/4.23/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      .buttons {
        position: absolute;
        bottom: 20px;
        left: 0;
        right: 0;
        text-align: center;
      .geoscene-button {
        display: inline;
        background-color: white;
        min-width: 200px;
        max-width: 300px;
    </style>

    <script>
      require([
  "geoscene/config",
  "geoscene/Map",
  "geoscene/views/SceneView",
  "geoscene/layers/SceneLayer",
  "geoscene/layers/FeatureLayer"
], function (geosceneConfig,Map, SceneView, SceneLayer, FeatureLayer) {
  geosceneConfig.apiKey = "YOUR_API_KEY";
  const buildings3DObjects = new SceneLayer({
    url:
      "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/SF_BLDG_WSL1/SceneServer",
    renderer: {
      type: "simple",
      symbol: {
        type: "mesh-3d",
        symbolLayers: [
          {
            type: "fill",
            material: {
              color: [255, 237, 204],
              colorMixMode: "replace"
            },
            edges: {
              type: "solid",
              color: [133, 108, 62, 0.5],
              size: 1
            }
          }
        ]
      }
    }
  });
  // 创建地图
  var map = new Map({
    basemap: "geoscene-light-gray",
    ground: "world-elevation",
    layers: [buildings3DObjects]
  // 创建 SceneView
  var view = new SceneView({
    container: "viewDiv",
    map: map,
    camera: {
      position: [-122.39899666, 37.77940678, 314.88439],
      heading: 356.82,
      tilt: 78.61
    qualityProfile: "high"
  document.getElementById("building").addEventListener("click", function (event) {
      type: "simple",
      symbol: {
        type: "mesh-3d",
        symbolLayers: [
            type: "fill",
            material: {
              color: [255, 237, 204],
              colorMixMode: "replace"
            edges: {
              type: "solid",
              color: [133, 108, 62, 0.5],
              size: 1
  document.getElementById("textured").addEventListener("click", function (event) {
    buildings3DObjects.renderer = null;
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div class="buttons">
      <button id="building" class="esri-button esri-button--secondary esri-button--half">Untextured 3D buildings</button>
      <button id="textured" class="esri-button esri-button--secondary esri-button--half">Textured 3D buildings</button>
    </div>
  </body>
</html>

逼真的城市可视化

在此示例中,法兰克福市使用集成的格网图层进行渲染。将包含感兴趣点的要素图层添加到地图中。这些点相对于场景放置,以便与格网的高度对齐。此外,可添加标注以显示该点的精确位置。有关高程对齐的详细信息,请参阅地形渲染页面

                                                                                                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>
      Realistic cities
    </title>
    <link rel="stylesheet" href="https://js.geoscene.cn/4.23/geoscene/themes/light/main.css" />
    <script src="https://js.geoscene.cn/4.23/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      #menu {
        padding: 1em;
    </style>

    <script>
      require([
        "geoscene/config",
        "geoscene/Map",
        "geoscene/views/SceneView",
        "geoscene/layers/IntegratedMeshLayer",
        "geoscene/widgets/LayerList",
        "geoscene/layers/SceneLayer",
        "geoscene/widgets/Legend"
      ], function (
        Map,
      ) {
        const map = new Map({
          basemap: "geoscene-imagery",
          ground: "world-elevation"
        const meshLayer = new IntegratedMeshLayer({
          url: "https://tiles.geoscene.cn/tiles/u0sSNqDXr7puKJrF/arcgis/rest/services/Frankfurt2017_v17/SceneServer/layers/0",
          copyright: "nFrames - Aerowest",
          title: "Integrated Mesh Frankfurt"
        });
        const color = [235, 171, 52];
        const poiLayer = new SceneLayer({
          url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Frankfurt_POIs/SceneServer",
          title: "Points of interest",
          renderer: {
            type: "simple",
            symbol: {
              type: "point-3d", // 自动转换为新的 PointSymbol3D()
              symbolLayers: [
                  type: "icon", // 自动转换为新的 IconSymbol3DLayer()
                  resource: {
                    primitive: "circle"
                  size: 10,
                  material: {
                    color: color
                  outline: {
                    color: "white",
                    size: 1
              verticalOffset: {
                screenLength: 40,
                maxWorldLength: 200,
                minWorldLength: 35
              callout: {
                type: "line", // 自动转换为新的 LineCallout3D()
                color: color,
                size: 1,
                border: {
                  color: "white"
          elevationInfo: {
            // 将在建筑或其他 SceneLayer 3D 对象的顶部放置点的高程模式
            mode: "relative-to-scene"
          screenSizePerspectiveEnabled: false,
          labelingInfo: [
              labelExpressionInfo: {
                value: "{name}"
              symbol: {
                type: "label-3d",
                symbolLayers: [
                    type: "text",
                    material: {
                      color: color
                    // 我们在字体上设置光环,使标签在任何背景下都更可见
                    halo: {
                      size: 1,
                      color: "white"
                    size: 10
        const view = new SceneView({
          container: "viewDiv",
          map: map,
          qualityProfile: "high",
          camera: {
            position: [
              8.69370363,
              50.10533415,
              284.73511
            heading: 295.75,
            tilt: 76.80
        const layerList = new LayerList({
          view: view
        view.ui.add(layerList, "top-right");
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>

将真实世界的城市对象添加为 3D 模型

您可以将单个城市元素(如树木、灯柱或长凳)添加为点的 3D 模型符号。在此示例中,汽车、树木和灯柱是具有 3D 模型符号的点几何。您可以以 glTF™ 格式使用自己的 3D 模型,也可以从作为 Web 样式提供的 3D 模型中进行选择。当您的目标是重新创建城市中某个区域的特写可视化时,这些模型非常有用。

在以下示例中,您可以添加具有特定 3D 模型符号的点。还可以对齐模型并调整其大小,以便与环境进行集成。单击 Tree 按钮,然后单击场景中放置树 3D 模型的位置。接下来,拖动圆圈处理器以调整其大小或旋转。

要创建此类可视化,请执行以下操作:

  1. 添加具有城市对象类型、旋转和大小属性的点要素图层。
  2. 设置唯一值渲染器,以将城市对象的类型映射到 web 样式库中的 3D 模型符号。
  3. 使用可视化变量按点要素图层中的属性驱动大小和旋转。
  4. 接下来,添加带有纹理建筑物的 3D 对象场景图层,以提高场景的真实感。
GeoScene JS API
                                                                                                                                                                                                                                                                                                                                                                                          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>
      Cities in 3D - models
    </title>
    <link rel="stylesheet" href="https://js.geoscene.cn/4.23/geoscene/themes/light/main.css" />
    <script src="https://js.geoscene.cn/4.23/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      #extra {
        max-width: 300px;
        padding: 10px;
        background-color: rgba(255, 255, 255, 0.9);
    </style>

    <script>
      require([
        "geoscene/config",
        "geoscene/WebScene",
        "geoscene/views/SceneView",
        "geoscene/layers/FeatureLayer",
        "geoscene/layers/SceneLayer",
        "geoscene/layers/GraphicsLayer",
        "geoscene/widgets/Sketch/SketchViewModel"
      ], function (geosceneConfig,WebScene, SceneView, FeatureLayer, SceneLayer, GraphicsLayer, SketchViewModel) {
        // 创建 Web 场景
        const map = new WebScene({
          basemap: "geoscene-imagery",
          ground: "world-elevation"
        // 创建视图
        const view = new SceneView({
          container: "viewDiv",
          map: map,
          camera: {
            position: {
              latitude: 39.957011,
              longitude: -75.169457,
              z: 26
            tilt: 78,
            heading: 315
          environment: {
            lighting: {
              date: new Date("June 15, 2015 16:00:00 EDT"),
              directShadowsEnabled: true,
              ambientOcclusionEnabled: true
        /********************************************************************
         ********************************************************************/
        // 方便功能,根据名称检索 WebStyleSymbols
        function getStreetSymbol(name) {
          return {
            type: "web-style", // 自动转换为新的 WebStyleSymbol()
            name: name,
            styleName: "EsriRealisticStreetSceneStyle"
        // 使用 UniqueValueRenderer 来代表不同的要素类型(路灯、垃圾桶)
        const streetFurnitureRenderer = {
          type: "unique-value", // 自动转换为新的 UniqueValueRenderer()
          field: "CATEGORY",
          defaultSymbol: getStreetSymbol("Light_On_Post_-_Light_on"),
          uniqueValueInfos: [
              value: "Overhanging street",
              symbol: getStreetSymbol("Overhanging_Street_-_Light_on")
              value: "Overhanging street and sidewalk",
              symbol: getStreetSymbol("Light_On_Post_-_Light_on")
              value: "Trash bin",
              symbol: getStreetSymbol("Trash_Bin_1")
              value: "Newspaper",
              symbol: getStreetSymbol("Newspaper_Vending_Machine")
              value: "Park bench 1",
              symbol: getStreetSymbol("Park_Bench_2")
          visualVariables: [
              type: "rotation",
              field: "ROTATION"
              type: "size",
              field: "SIZE",
              axis: "height"
        // 创建图层并为其分配渲染器
        const streetFurnitureLayer = new FeatureLayer({
          url:
            "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Philadelphia_LoganSquare_streetFurniture/FeatureServer/0",
          renderer: streetFurnitureRenderer,
          elevationInfo: {
            mode: "on-the-ground"
        /**********************************************
         **********************************************/
        // 将要素属性值映射到 Web 样式符号名称的便利对象
        // 将用于在渲染器中创建 uniqueValueInfos
        const transportationSymbols = [
            value: "Bus",
            name: "Bus"
            value: "Taxi",
            name: "Taxi"
            value: "Ambulance",
            name: "Ambulance"
            value: "Porsche",
            name: "Porsche_Carrera"
            value: "Mercedes",
            name: "Mercedes_S-Class"
            value: "Ford",
            name: "Ford_Edge"
            value: "Audi",
            name: "Ford_Edge"
            value: "Volkswagen",
            name: "Volkswagen_Jetta_Wagon"
        const transportationLayer = new FeatureLayer({
          url:
            "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Philadelphia_LoganSquare_cars/FeatureServer",
          outFields: ["ROTATION", "CATEGORY", "SIZE"],
          renderer: {
            type: "unique-value", // 自动转换为新的 UniqueValueRenderer()
            field: "CATEGORY",
            uniqueValueInfos: transportationSymbols.map(function (type) {
              return {
                value: type.value,
                symbol: {
                  type: "web-style", // 自动转换为新的 WebStyleSymbol()
                  name: type.name,
                  styleName: "EsriRealisticTransportationStyle"
                }
              };
            }),
            visualVariables: [
              {
                type: "rotation",
                // 汽车需要有一个旋转场,以便与街道对齐
                field: "ROTATION"
              },
              {
                type: "size",
                field: "SIZE",
                axis: "depth"
              }
            ]
          },
          elevationInfo: {
            mode: "on-the-ground"
          }
        });
        /**********************************************
         **********************************************/
        // 定义唯一值
        const uniqueValueInfos = [
            value: "Acer",
            symbol: {
              type: "web-style", // 自动转换为新的 WebStyleSymbol()
              name: "Acer",
              styleName: "EsriRealisticTreesStyle"
            value: "Bulbophyllum",
            symbol: {
              type: "web-style", // 自动转换为新的 WebStyleSymbol()
              name: "Bulbophyllum",
              styleName: "EsriRealisticTreesStyle"
            value: "Cornus",
            symbol: {
              type: "web-style", // 自动转换为新的 WebStyleSymbol()
              name: "Cornus",
              styleName: "EsriRealisticTreesStyle"
            value: "Pinus",
            symbol: {
              type: "web-style", // 自动转换为新的 WebStyleSymbol()
              name: "Pinus",
              styleName: "EsriRealisticTreesStyle"
        // 定义 vegetationLayer
        const vegetationLayer = new FeatureLayer({
          url:
            "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Philadelphia_LoganSquare_vegetation_selection/FeatureServer",
          elevationInfo: {
            mode: "on-the-ground"
          renderer: {
            type: "unique-value", // 自动转换为新的 UniqueValueRenderer()
            field: "CATEGORY",
            defaultSymbol: {
              type: "web-style", // 自动转换为新的 WebStyleSymbol()
              name: "Acer",
              styleName: "EsriRealisticTreesStyle"
            uniqueValueInfos: uniqueValueInfos,
            visualVariables: [
                type: "size",
                field: "SIZE",
                axis: "height" // 从 SIZE 字段中获取植物的实际高度
                type: "rotation",
                valueExpression: "random() * 360" // 我们使用随机旋转,使植物看起来不同
        const buildings = new SceneLayer({
          url: "https://tiles.geoscene.cn/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/philadelphia_Bldgs_text_untex/SceneServer",
          elevationInfo: {
            mode: "absolute-height",
            offset: -6
        view.ui.add("extra", "bottom-right");
        const graphicsLayer = new GraphicsLayer({
          elevationInfo: { mode: "on-the-ground" }
        const treeBtn = document.getElementById("tree");
        const busBtn = document.getElementById("bus");
          .when(function () {
            // 此示例使用 SketchViewModel 向 GraphicsLayer 添加点。
            // 这些点以 3D glTF 模型作为符号。
            const sketchVM = new SketchViewModel({
              layer: graphicsLayer,
              view: view
            treeBtn.addEventListener("click", function () {
              // 在 ObjectSymbol3DLayer 的资源中
              // 引用 glTF 模型的相对路径
                type: "point-3d",
                symbolLayers: [
                    type: "object",
                    resource: {
                      href:
                        "https://static.geoscene.cn/arcgis/styleItems/RealisticTrees/web/resource/AcerPlatanoides.json"
              sketchVM.create("point");
              this.classList.add("esri-button--secondary");
            busBtn.addEventListener("click", function () {
              // 在 ObjectSymbol3DLayer 的资源中
              // 引用 glTF 模型的相对路径
                type: "point-3d",
                symbolLayers: [
                    type: "object",
                    resource: {
                      href:
                        "https://static.geoscene.cn/arcgis/styleItems/RealisticTransportation/web/resource/Bus.json"
              sketchVM.create("point");
              this.classList.add("esri-button--secondary");
            sketchVM.on("create", function (event) {
              if (event.state === "complete") {
          .catch(console.error);
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="extra" class="geoscene-widget">
        <p>Select a symbol and place it in the scene:</p>
        <button id="tree" class="geoscene-button">Tree</button><br />
        <button id="bus" class="geoscene-button">Bus</button>
        <p>Discover more 3D symbols in the
      <a
        href="../../../guide/geoscene-web-style-symbols-3d/index.html"
        target="_blank"
        >Esri 3D Web Style Symbols</a
      > list.</p>
    </div>
  </body>
</html>

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.