在3D城市中可视化拟建建筑

在3D城市中可视化拟建建筑

Flying
2020-10-09 / 0 评论 / 261 阅读 / 正在检测是否收录...

在本教程中,您将学习如何创建一个 Cesium 应用程序以用您自己的 3D 模型替换真实城市中的建筑物。

您可以使用它来可视化拟建建筑物的影响。它如何改变天际线?从特定楼层或房间看去会是什么样子?

我们将介绍如何:

  • 在网络上设置和部署您的 Cesium 应用程序
  • 添加全球 3D 建筑、地形和图像的基础图层
  • 隐藏单个建筑物并用您自己的 3D 模型替换它们

这是您将构建的应用程序。您可以切换建议的建筑物并从多个角度查看它。

开始之前

我们将从 Cesium ion 获取全球卫星图像、3D 建筑和地形,Cesium ion 是一个用于流式传输和托管 3D 内容的开放平台。 如果您还没有免费的 Cesium ion 帐户,请注册一个

登录后:

  1. 转到您的 Access Tokens 选项卡。
  2. 请注意默认令牌旁边的复制按钮。我们将在下一步中使用此令牌。
Cesiumion 是一个用于流式传输和托管 3D 内容的开放平台,包括全球精选数据,您可以使用这些数据创建自己的真实世界应用程序。

quickstart_token.jpg

步骤1:设置你的Cesium 应用

我们将使用开源 JavaScript 引擎 CesiumJS 创建我们的应用程序。我们将使用在线 IDE Glitch 来托管我们的应用程序。

  1. 使用我们放在一起的基本模板创建一个新的 Glitch 项目
  2. 单击左侧面板中的 index.html 查看应用程序代码。
  3. 替换为您的令牌页面 your_token_here 中的访问令牌 。
  4. 通过单击顶部的 Show 并选择 Next to The Code 来运行应用程序。

show_app.jpg

到目前为止,index.html 中的代码做了三件事:

  • 导入 CesiumJS 库。JavaScript和 CSS 文件在这两行中加载:
<script src="https://cesium.com/downloads/cesiumjs/releases/1.100/Build/Cesium/Cesium.js"></script>
<link
  href="https://cesium.com/downloads/cesiumjs/releases/1.100/Build/Cesium/Widgets/widgets.css"
  rel="stylesheet"
/>
  • 为场景添加一个 HTML 容器:<div id=cesiumContainer></div>
  • 初始化查看器:const viewer = new Cesium.Viewer('cesiumContainer');

你现在有一个基本的 CesiumJS 应用程序在你的浏览器中运行,其中包含来自 Cesium ion 的全球卫星图像。

配置自动刷新

每次代码更改时,Glitch 都会自动刷新页面。您可以通过单击左上角的项目名称并取消选中此框来切换它:

auto_refresh.jpg

使用应用程序窗口顶部的刷新按钮重新运行应用程序:

refresh.jpg

步骤 2:添加 Cesium OSM 建筑和 Cesium 世界地形

Cesium OSM Buildings 是一个全球基础层,拥有超过 3.5 亿个来自 OpenStreetMap 数据的建筑物。它用作 3D Tiles,这是 Cesium 创建的开放标准,可以将 3D 内容流式传输到任何兼容的客户端。

让我们添加这些图层,然后将相机移动到我们虚构的新建筑所在的城市 — 科罗拉多州丹佛市。

  1. 用下面的代码替换 index.html 中的 JavaScript 代码,保留之前的访问令牌行。
  2. 单击并拖动以移动相机。拖动时按住 CTRL 以倾斜。
  3. 单击任何建筑物以查看其元数据。
// Keep your Cesium.Ion.defaultAccessToken = 'your_token_here' line above. 
// STEP 2 CODE
// Initialize the viewer with Cesium World Terrain.
const viewer = new Cesium.Viewer('cesiumContainer', {
  terrainProvider: Cesium.createWorldTerrain()
});
// Add Cesium OSM Buildings.
const buildingsTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings());
// Fly the camera to Denver, Colorado at the given longitude, latitude, and height.
viewer.camera.flyTo({
  destination: Cesium.Cartesian3.fromDegrees(-104.9965, 39.74248, 4000)
});

此时,您完整的 index.html 将如下所示(访问令牌除外)。在以后的步骤中,您将在标记内的现有代码下方添加新代码 script。

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.100/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.100/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
  <link href="style.css" rel="stylesheet">
</head>
<body>
  <div id="cesiumContainer"></div>
  <script>
    // Your access token can be found at: https://cesium.com/ion/tokens.
    // This is the default access token from your ion account
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3ODdlN2I5OS1iZDMyLTQ2MTItODQwYi01MGE3NGI3NGIzNGUiLCJpZCI6MTE4MjU5LCJpYXQiOjE2NzA5ODI0MDd9.XpfuSxbcNuxNF1jMqI5FxveHXhiq6VVCsww80hIVAME';
    
    // Keep your Cesium.Ion.defaultAccessToken = 'your_token_here' line above. 
    // STEP 2 CODE
    // Initialize the viewer with Cesium World Terrain.
    const viewer = new Cesium.Viewer('cesiumContainer', {
      terrainProvider: Cesium.createWorldTerrain()
    });
    // Add Cesium OSM Buildings.
    const buildingsTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings());
    // Fly the camera to Denver, Colorado at the given longitude, latitude, and height.
    viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(-104.9965, 39.74248, 4000)
    });
  </script>
</body>
</html>
Cesium OSM Buildings 与全球高分辨率 3D 地形图层 Cesium World Terrain 绑定。这使其非常适合需要精确建筑高度的应用,例如洪水分析工具。

步骤 3:确定新建建筑面积

在我们添加新建筑物之前,让我们添加一个 GeoJSON 文件来标记它的足迹。这将告诉我们哪些现有建筑物需要拆除。

  1. 下载 GeoJSON 文件。
  2. 将 GeoJSON 文件拖放到您的 Cesium ion 仪表板中。
  3. 上传

步骤 4:上传后,记下预览窗口下的资产 ID。

asset_id.jpg

  1. 在 index.html 中添加以下代码。
  • 替换 your_asset_id 为您的资产 ID。ID 是一个数字,因此您不需要引号。
// STEP 3 CODE
async function addBuildingGeoJSON() {
  // Load theGeoJSONfile from Cesium ion.
  const geoJSONURL = await Cesium.IonResource.fromAssetId(your_asset_id);
  // Create the geometry from the GeoJSON, and clamp it to the ground.
  constGeoJSON= await Cesium.GeoJsonDataSource.load(geoJSONURL, { clampToGround: true });
  // Add it to the scene.
  const dataSource = await viewer.dataSources.add(geoJSON);
  // By default, polygons in CesiumJS will be draped over all3Dcontent in the scene.
  // Modify the polygons so that this draping only applies to the terrain, not3Dbuildings.
  for (const entity of dataSource.entities.values) {
    entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN;
  }
  // Move the camera so that the polygon is in view.
  viewer.flyTo(dataSource);
}
addBuildingGeoJSON();

您现在会在地面上看到建筑物的足迹。使用鼠标滚轮放大或右键单击并拖动以仔细查看。

building_footprint.jpg

步骤 5:隐藏现场现有的 3D 建筑

现在我们已经确定了新建筑的去向,我们可以看到当前有哪些建筑。我们将使用 3D Tiles Styling Language 来隐藏它们。

在上面的占地面积中,我们可以看到在我们拟建的新建筑所在地有六座建筑——一座大型建筑和五座小得多的建筑。

  1. 添加以下代码。它隐藏了所有较小的 3D 建筑。
// STEP 4 CODE
// Hide individual buildings in this area using3DTiles Styling language.
buildingsTileset.style = new Cesium.Cesium3DTileStyle({
  // Create a style rule to control each building's "show" property.
  show: {
    conditions : [
      // Any building that has this elementId will have `show = false`.
      ['${elementId} === 332469316', false],
      ['${elementId} === 332469317', false],
      ['${elementId} === 235368665', false],
      ['${elementId} === 530288180', false],
      ['${elementId} === 530288179', false],
      // If a building does not have one of these elementIds, set `show = true`.
      [true, true]
    ]
  },
  // Set the default color style for this particular3DTileset.
  // For any building that has a `cesium#color` property, use that color, otherwise make it white.
  color: "Boolean(${feature['cesium#color']}) ? color(${feature['cesium#color']}) : color('#ffffff')"
});
  1. 扩展此代码以隐藏剩余的 3D 建筑。
  • 单击建筑物以找到其elementI
  • 添加另一行,如:['${elementId} === large_building_elementId', false]

步骤 6:上传并定位新建筑

让我们上传建议的建筑模型。

  1. 下载此 glTF 模型。
  2. 将其拖放到您的 Cesium 离子仪表板中。
  3. 选择 3D Model (tile as 3D Tiles) 并按上传
  4. 完成拼贴后,单击 资产预览窗口顶部的 Adjust Tileset Location 按钮。

adjust_tileset_location.jpg

  1. 在搜索框中输入建筑物地址 1250 Cherokee Street ,然后单击 下一步
  2. 使用查看器上的控件,在视觉上定位和旋转建筑物,使其与下面的卫星图像对齐。您的最终设置应大致为:
经度:-104.9909
纬度:39.73579
身高:1577
航向:-8
  1. 保存

确保地理定位准确性

在本教程中,您手动定位了一座新建筑。如果建筑物已经进行了地理参考,Cesium ion 会自动将其放置在正确的位置。您还可以使用 REST API 对其进行地理定位。通过地理定位指南了解更多信息 。

步骤 7:将新建筑添加到场景中

现在让我们将新建筑物添加到场景中。

  1. 在资产预览窗口下获取我们刚刚地理定位的建筑模型的资产 ID。
  2. index.html 中添加以下代码。
  • 替换 your_asset_id 为您的资产 ID。
// STEP 6 CODE
// Add the3DTileset you created from your Cesium ion account.
const newBuildingTileset = viewer.scene.primitives.add(
  new Cesium.Cesium3DTileset({
    url: Cesium.IonResource.fromAssetId(your_asset_id)
  })
);
// Move the camera to the new building.
viewer.flyTo(newBuildingTileset);

步骤 8:添加一个按钮来切换新建筑

  1. index.html 中,将按钮添加到您的 <body> 标签内的上方<script
<button id="toggle-building">Toggle new building</button>
  1. 在 head 标签内添加以下 CSS style标签:
<style type="text/css">
  #toggle-building { z-index: 1; position: fixed; top: 5px; left: 5px; }
</style>
  1. index.html 中添加以下 JavaScript:
// STEP 7 CODE
// Toggle the tileset's show property when the button is clicked.
document.querySelector('#toggle-building').onclick = function() {
  newBuildingTileset.show = !newBuildingTileset.show;
};

步骤 9:考虑建筑对周围环境的影响

现在您可以比较有和没有这座新建筑的场景!

丹佛的全景山景备受推崇。这座建筑如何影响其他地方的景色,例如科罗拉多州议会大厦?

denver-skyline.jpg
对科罗拉多州议会大厦景观的影响。
要重现这一点,请搜索美国科罗拉多州丹佛市的州议会大厦并调整相机。

我们甚至可以探索国会大厦入口处的景色将如何变化。

denver-skyline-from-ground.jpg
从更接近地面的角度对视图的影响。

完整教程源码

这是带有 your_token_hereyour_asset_id 占位符的此应用程序的完整源代码。

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.100/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.100/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
  <link href="style.css" rel="stylesheet">
  <style type="text/css">
    #toggle-building { z-index: 1; position: fixed; top: 5px; left: 5px; }
  </style>
</head>
<body>
  <div id="cesiumContainer"></div>
  <button id="toggle-building">Toggle new building</button>
  
  <script>
    // Your access token can be found at: https://cesium.com/ion/tokens.
    // This is the default access token from your ion account
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3ODdlN2I5OS1iZDMyLTQ2MTItODQwYi01MGE3NGI3NGIzNGUiLCJpZCI6MTE4MjU5LCJpYXQiOjE2NzA5ODI0MDd9.XpfuSxbcNuxNF1jMqI5FxveHXhiq6VVCsww80hIVAME';

    // Keep your Cesium.Ion.defaultAccessToken = 'your_token_here' line from above. 
    // STEP 2 CODE
    // Initialize the viewer with Cesium World Terrain.
    const viewer = new Cesium.Viewer('cesiumContainer', {
      terrainProvider: Cesium.createWorldTerrain()
    });
    // Add Cesium OSM Buildings.
    const buildingsTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings());
    // Fly the camera to Denver, Colorado at the given longitude, latitude, and height.
    /* viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(-104.9965, 39.74248, 4000)
    }); */

    // STEP 3 CODE
    async function addBuildingGeoJSON() {
      // Load theGeoJSONfile from Cesium ion.
      const geoJSONURL = await Cesium.IonResource.fromAssetId(your_asset_id);
      // Create the geometry from the GeoJSON, and clamp it to the ground.
      constGeoJSON= await Cesium.GeoJsonDataSource.load(geoJSONURL, { clampToGround: true });
      // Add it to the scene.
      const dataSource = await viewer.dataSources.add(geoJSON);
      // By default, polygons in CesiumJS will be draped over all3Dcontent in the scene.
      // Modify the polygons so that this draping only applies to the terrain, not3Dbuildings.
      for (const entity of dataSource.entities.values) {
        entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN;
      }
      // Move the camera so that the polygon is in view.
      // viewer.flyTo(dataSource);
    }
    addBuildingGeoJSON();

    // STEP 4 CODE
    // Hide individual buildings in this area using3DTiles Styling language.
    buildingsTileset.style = new Cesium.Cesium3DTileStyle({
      // Create a style rule to control each building's "show" property.
      show: {
        conditions : [
          // Any building that has this elementId will have `show = false`.
          ['${elementId} === 532245203', false],
          ['${elementId} === 332469316', false],
          ['${elementId} === 332469317', false],
          ['${elementId} === 235368665', false],
          ['${elementId} === 530288180', false],
          ['${elementId} === 530288179', false],
          // If a building does not have one of these elementIds, set `show = true`.
          [true, true]
        ]
      },
      // Set the default color style for this particular3DTileset.
      // For any building that has a `cesium#color` property, use that color, otherwise make it white.
      color: "Boolean(${feature['cesium#color']}) ? color(${feature['cesium#color']}) : color('#ffffff')"
    });

    // STEP 6 CODE
    // Add the3DTileset you created from your Cesium ion account.
    const newBuildingTileset = viewer.scene.primitives.add(
      new Cesium.Cesium3DTileset({
        url: Cesium.IonResource.fromAssetId(your_asset_id)
      })
    );
    // Move the camera to the new building.
    viewer.flyTo(newBuildingTileset);

    // STEP 7 CODE
    // Toggle the tileset's show property when the button is clicked.
    document.querySelector('#toggle-building').onclick = function() {
      newBuildingTileset.show = !newBuildingTileset.show;
    };
  </script>
</body>
</html>

下一步

如果您有自己的建筑模型,请尝试使用它而不是提供的示例 —— glTF、OBJ 和 FBX 都受支持。或者将建筑物放置在您自己的城市中。

请参阅 3D 模型导入指南以了解更多信息。

2

评论 (0)

取消