返回 导航

Vue.js

hangge.com

Vue.js - 集成Cesium构建三维可视化场景教程8(加载官方Ion 3D Tiles)

作者:hangge | 2026-07-13 09:14
    如果说 Entity(实体)是场景中的“点缀”,那么 3D Tiles 就是场景的“骨架”。无论是城市级别的白模、高精度的倾斜摄影,还是复杂的 BIM 建筑模型,都是通过 3D Tiles 技术呈现在浏览器中的。下面我将通过样例演示如何创建 3D Tiles 实例并添加到场景中。

八、加载 Ion 3D Tiles

1,基本介绍

(1)3D Tiles 是用于流式传输大规模异构 3D 地理空间数据集的开放规范,由 Cesium 团队创建并已成为 OGC 社区标准。它支持海量三维模型、点云、摄影测量数据的可视化。

(2)3D Tiles 的核心逻辑是 LOD(分级细节):
  • 远景:加载低分辨率的切片。
  • 近景:加载高分辨率的切片。
  • 结构:由一个 tileset.json 文件作为入口,索引众多的 .b3dm.i3dm.pnts 文件。

(3)3D Tiles 支持按需流式加载、细粒度裁剪和样式化。对大型三维可视化场景(城市级/园区级)非常重要,能显著减少首屏加载量并保证交互流畅。

2,加载全球建筑白模样例

(1)Cesium 官方提供了许多 3D Tiles 资产,其中最经典的就是 Cesium OSM Buildings(全球建筑白模),下面代码我们就是用该资产为例进行演示。
<template>
    <div class="layer-container">
        <div ref="cesiumContainer" class="cesium-container"></div>

        <!-- 加载状态 -->
        <div v-if="loading" class="loading-overlay">
            <div class="loading-spinner"></div>
            <p>加载三维场景中...</p>
        </div>
    </div>
</template>

<script>
// 引入 Cesium 核心类
import * as Cesium from "cesium";

export default {
    name: 'CesiumViewer',

    data() {
        return {
            viewer: null,
            loading: true,
            terrainEnabled: true,
            sampleEntities: [],
            longitude: '',
            latitude: '',
            height: '',
        }
    },

    mounted() {
        // 确保 Cesium 已加载
        if (typeof Cesium === 'undefined') {
            console.error('Cesium 未加载,请检查配置')
            this.loading = false
            return
        }

        // 初始化 Cesium 场景
        this.initCesium()
    },

    beforeDestroy() {
        // 组件销毁时清理资源
        this.destroyCesium()
    },

    methods: {
        // 初始化 Cesium
        async initCesium() {
            try {
                // 配置 Cesium 访问令牌
                //Cesium.Ion.defaultAccessToken = '你的token'

                // 创建 Viewer 实例
                this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
                    animation: false, // 是否显示动画控件
                    baseLayerPicker: false, // 是否显示图层选择控件
                    fullscreenButton: false, // 是否显示全屏按钮
                    geocoder: false, // 是否显示地理编码搜索控件
                    homeButton: false, // 是否显示Home按钮
                    infoBox: false, // 是否显示信息框
                    sceneModePicker: false, // 是否显示3D/2D选择器
                    selectionIndicator: false, // 是否显示选取指示器组件
                    timeline: false, // 是否显示时间轴
                    navigationHelpButton: false, // 是否显示帮助按钮
                    scene3DOnly: true, // 每个几何实例仅以3D渲染以节省GPU内存
                    shouldAnimate: true, // 自动播放动画
                    // 地形配置
                    terrainProvider: await Cesium.createWorldTerrainAsync()
                })

                // 强制重新计算画布尺寸
                this.viewer.canvas.width = this.viewer.container.clientWidth;
                this.viewer.canvas.height = this.viewer.container.clientHeight;
                this.viewer.resize(); // 核心方法:告知 Cesium 容器大小已变

                // 加载 Cesium Ion 3D Tiles(全球建筑白模)
                const tileset = await Cesium.createOsmBuildingsAsync()
                this.viewer.scene.primitives.add(tileset)

                // 设置初始视图
                this.setInitialView()

                // 加载完成
                this.loading = false

                console.log('Cesium 场景初始化完成')
            } catch (error) {
                console.error('初始化 Cesium 失败:', error)
                this.loading = false
            }
        },

        // 设置初始视图
        setInitialView() {
            // 设置初始位置(例如:北京天安门)
            const initialPosition = Cesium.Cartesian3.fromDegrees(116.3974, 39.9093, 1500)
            this.viewer.camera.setView({
                destination: initialPosition,
                orientation: {
                    heading: Cesium.Math.toRadians(0),
                    pitch: Cesium.Math.toRadians(-90),
                    roll: 0
                }
            })
        },

        // 销毁 Cesium 资源
        destroyCesium() {
            if (this.viewer) {
                this.viewer.destroy()
                this.viewer = null
            }
        }
    }
}
</script>

<style scoped>
.layer-container {
    position: relative;
    width: 100%;
    height: 100%;
}


.cesium-container {
    width: 100%;
    height: 100%;
}

.loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 1000;
    color: white;
}

.loading-spinner {
    border: 4px solid rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    border-top: 4px solid #42b983;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
    margin-bottom: 15px;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}
</style>

(2)运行效果如下,可以看到地图上会自动加载北京周边的 3D 建筑白模,缩放时可明显看到 LOD 切换,并且建筑数量随视野动态变化。

(3)按下鼠标中键然后拖动改变视角,可以看地更明显些。

3,加载墨尔本摄影测量数据

(1)下面代码我们使用 Cesium.Cesium3DTileset.fromUrl 加载墨尔本摄影测量的 3D Tiles 数据,该数据集完整表示了墨尔本市范围内的所有物理要素,包括建筑物、树木以及地形。
<template>
    <div class="layer-container">
        <div ref="cesiumContainer" class="cesium-container"></div>

        <!-- 加载状态 -->
        <div v-if="loading" class="loading-overlay">
            <div class="loading-spinner"></div>
            <p>加载三维场景中...</p>
        </div>
    </div>
</template>

<script>
// 引入 Cesium 核心类
import * as Cesium from "cesium";

export default {
    name: 'CesiumViewer',

    data() {
        return {
            viewer: null,
            loading: true,
            terrainEnabled: true,
            sampleEntities: [],
            longitude: '',
            latitude: '',
            height: '',
        }
    },

    mounted() {
        // 确保 Cesium 已加载
        if (typeof Cesium === 'undefined') {
            console.error('Cesium 未加载,请检查配置')
            this.loading = false
            return
        }

        // 初始化 Cesium 场景
        this.initCesium()
    },

    beforeDestroy() {
        // 组件销毁时清理资源
        this.destroyCesium()
    },

    methods: {
        // 初始化 Cesium
        async initCesium() {
            try {
                // 配置 Cesium 访问令牌
                Cesium.Ion.defaultAccessToken = '你的token'

                // 创建 Viewer 实例
                this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
                    animation: false, // 是否显示动画控件
                    baseLayerPicker: false, // 是否显示图层选择控件
                    fullscreenButton: false, // 是否显示全屏按钮
                    geocoder: false, // 是否显示地理编码搜索控件
                    homeButton: false, // 是否显示Home按钮
                    infoBox: false, // 是否显示信息框
                    sceneModePicker: false, // 是否显示3D/2D选择器
                    selectionIndicator: false, // 是否显示选取指示器组件
                    timeline: false, // 是否显示时间轴
                    navigationHelpButton: false, // 是否显示帮助按钮
                    scene3DOnly: true, // 每个几何实例仅以3D渲染以节省GPU内存
                    shouldAnimate: true, // 自动播放动画
                    // 地形配置 
                    terrainProvider: await Cesium.createWorldTerrainAsync()
                })

                // 强制重新计算画布尺寸
                this.viewer.canvas.width = this.viewer.container.clientWidth;
                this.viewer.canvas.height = this.viewer.container.clientHeight;
                this.viewer.resize(); // 核心方法:告知 Cesium 容器大小已变

                // 加载墨尔本摄影测量数据
                const tileset = await Cesium.Cesium3DTileset.fromUrl('https://tiles.arcgis.com/tiles/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Utrecht_3D_Tiles_Integrated_Mesh/3DTilesServer/tileset.json')
                this.viewer.scene.primitives.add(tileset)
                this.viewer.zoomTo(tileset)

                // 加载完成
                this.loading = false

                console.log('Cesium 场景初始化完成')
            } catch (error) {
                console.error('初始化 Cesium 失败:', error)
                this.loading = false
            }
        },

        // 销毁 Cesium 资源
        destroyCesium() {
            if (this.viewer) {
                this.viewer.destroy()
                this.viewer = null
            }
        }
    }
}
</script>

<style scoped>
.layer-container {
    position: relative;
    width: 100%;
    height: 100%;
}


.cesium-container {
    width: 100%;
    height: 100%;
}

.loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 1000;
    color: white;
}

.loading-spinner {
    border: 4px solid rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    border-top: 4px solid #42b983;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
    margin-bottom: 15px;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}
</style>

(2)运行效果如下:


附一:加载我们自己的 Cesium Ion 3D Tiles

(1)Cesium 官方提供的 3D Tiles 资源可能并不能完全满足我们的需求,我们可以制作自己的 3D Tiles。首先上传数据到 Ion,我们可以上传数据到 Ion,包括:
  • 倾斜摄影(OSGB / OBJ / FBX
  • BIMIFC
  • GLB / Gltf
  • 点云(LAS / LAZ

(2)Cesium Ion 会自动进行如下一些列操作:
  • 将其转换为 3D Tiles
  • 生成生成 LOD
  • 提供 Asset ID
(3)最后我们代码中通过 Asset ID (例如下面的 123456)加载进来即可。
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(123456)
viewer.scene.primitives.add(tileset)
viewer.zoomTo(tileset)

附二、只显示 3D Tiles

(1)如果我们希望只显示 3D Tiles,不显示任何地图、影像或地形。可以设置不加载任何底图(Bing 地图),也不加载地形(Terrain)。如果需要,我们还可以设置下背景色(需要关闭天空盒子、大气等)
// 创建 Viewer 实例
this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
    imageryProvider: false, // 不加载影像
    terrainProvider: new Cesium.EllipsoidTerrainProvider(), // 数学椭球,不会请求任何地形数据
    baseLayerPicker: false,
    geocoder: false,
    timeline: false,
    animation: false,
    sceneModePicker: false
})

const scene = this.viewer.scene
// 彻底关闭天空盒(有些版本必须用 undefined)
scene.skyBox = undefined
// 彻底关闭大气
scene.skyAtmosphere = undefined
// 关闭雾效(否则仍可能偏蓝)
scene.fog.enabled = false
// 如果 globe 存在,也关掉
scene.globe && (scene.globe.show = false)
// 设置背景色(最后设置)
scene.backgroundColor = Cesium.Color.fromCssColorString('#EDF2FA')

// 加载 Cesium Ion 3D Tiles(全球建筑白模)
const tileset = await Cesium.createOsmBuildingsAsync()
this.viewer.scene.primitives.add(tileset)

(2)只显示全球建筑白模 3D Tiles 数据效果如下:

(3)只显示墨尔本摄影测量 3D Tiles 数据效果如下:
评论

全部评论(0)

回到顶部