开源库入门教程 Cesium:3D地球和地图库

文章目录

最近在做项目时需要展示地理数据,我尝试了好几个库后才发现了Cesium这个宝藏!它让我能够在浏览器中创建惊艳的3D地球和地图应用。今天就和大家分享一下我使用Cesium的心得和入门步骤,希望对你有所帮助!

Cesium是什么?

Cesium是一个开源的JavaScript库,专门用于创建高性能的3D地球和地图应用。它最初由AGI(Analytical Graphics, Inc.)公司在2012年开发,现在由Cesium GS公司维护。

Cesium最厉害的地方在于它能在网页浏览器中渲染完整的3D地球,而且不需要任何插件(这点真的太棒了)!它直接使用WebGL技术,所以在现代浏览器中都能流畅运行。

为什么选择Cesium?

在众多地图库中,Cesium有几个突出优势:

  1. 真正的3D地球 - 不同于很多2D地图库,Cesium提供了一个完整的3D地球模型,支持从太空到街道级别的无缝缩放。

  2. 时间动态数据 - Cesium有一个内置的时间轴控件,可以展示随时间变化的数据(比如卫星轨道、天气变化等)。

  3. 精确的地理参考 - 支持各种坐标系统和地理投影,保证数据在地球上的准确位置。

  4. 海量数据处理能力 - 能够高效处理大量的地理数据,包括地形、影像和矢量数据。

  5. 活跃的社区支持 - 有完善的文档和活跃的社区,遇到问题很容易找到解决方案。

快速上手Cesium

接下来,我会带你从零开始搭建一个简单的Cesium应用。相信我,比你想象的要简单!

安装和配置

有几种方式可以在项目中使用Cesium:

方法1:使用npm安装(适合现代前端工程)
bash 复制代码
npm install cesium

安装后,还需要配置一下webpack或其他打包工具,因为Cesium包含了一些静态资源需要特殊处理。

方法2:使用CDN(最简单的方式)

如果你只是想快速尝试,直接在HTML中引入CDN链接就可以了:

html 复制代码
<script src="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Widgets/widgets.css" rel="stylesheet">

注意版本号可能会更新,建议去官网查看最新版本。

创建你的第一个Cesium应用

下面是一个最基础的Cesium应用示例:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>我的第一个Cesium应用</title>
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Cesium.js"></script>
    <link href="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    <style>
        html, body, #cesiumContainer {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="cesiumContainer"></div>
    <script>
        // 你需要一个Cesium ion账号获取token
        Cesium.Ion.defaultAccessToken = '你的Cesium ion token';
        
        // 创建Cesium查看器
        const viewer = new Cesium.Viewer('cesiumContainer', {
            terrain: Cesium.Terrain.fromWorldTerrain(),
            // 开启大气效果
            skyAtmosphere: true,
            // 显示底图选择器
            baseLayerPicker: true
        });
        
        // 设置初始视图为北京
        viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(116.4074, 39.9042, 15000),
            orientation: {
                heading: Cesium.Math.toRadians(0),
                pitch: Cesium.Math.toRadians(-90),
                roll: 0.0
            }
        });
    </script>
</body>
</html>

这段代码会创建一个基本的3D地球,并将视角定位到北京上空。你需要注册一个Cesium ion账号来获取免费的token,这样才能访问Cesium提供的地形和影像服务。

Cesium的核心概念

在开始创建复杂应用前,有必要了解Cesium的几个核心概念:

1. Viewer(查看器)

Viewer是Cesium应用的核心组件,它包含了3D地球和一系列控件。创建一个Viewer非常简单:

javascript 复制代码
const viewer = new Cesium.Viewer('cesiumContainer');

Viewer提供了很多配置选项,例如:

javascript 复制代码
const viewer = new Cesium.Viewer('cesiumContainer', {
    terrain: Cesium.Terrain.fromWorldTerrain(), // 加载全球地形
    timeline: true, // 显示时间轴
    animation: true, // 显示动画控件
    baseLayerPicker: true, // 显示底图选择器
    sceneModePicker: true, // 显示场景模式选择器
    navigationHelpButton: true, // 显示帮助按钮
    infoBox: true, // 显示信息框
    fullscreenButton: true // 显示全屏按钮
});

2. Entity(实体)

Entity是Cesium中表示地理对象的基本方式,可以是点、线、面、模型等。例如,添加一个点标记:

javascript 复制代码
viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(116.4074, 39.9042),
    point: {
        pixelSize: 10,
        color: Cesium.Color.RED
    },
    label: {
        text: '北京',
        font: '14pt sans-serif',
        pixelOffset: new Cesium.Cartesian2(0, -20)
    }
});

3. DataSource(数据源)

DataSource用于加载和管理大量实体数据,支持多种格式如GeoJSON、KML、CZML等:

javascript 复制代码
// 加载GeoJSON数据
const dataSource = Cesium.GeoJsonDataSource.load('data/china.geojson', {
    stroke: Cesium.Color.BLUE,
    fill: Cesium.Color.BLUE.withAlpha(0.5),
    strokeWidth: 3
});
viewer.dataSources.add(dataSource);

4. Primitive(图元)

Primitive是更底层的渲染对象,比Entity性能更高,适合渲染大量图形:

javascript 复制代码
// 创建一个蓝色矩形
const instance = new Cesium.GeometryInstance({
    geometry: new Cesium.RectangleGeometry({
        rectangle: Cesium.Rectangle.fromDegrees(115, 39, 117, 41),
        vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
    }),
    attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE.withAlpha(0.5))
    }
});

viewer.scene.primitives.add(new Cesium.Primitive({
    geometryInstances: instance,
    appearance: new Cesium.PerInstanceColorAppearance()
}));

5. Camera(相机)

Camera控制视角,可以通过编程方式控制飞行和视角:

javascript 复制代码
// 飞行到特定位置
viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(121.5, 31.2, 10000), // 上海
    orientation: {
        heading: Cesium.Math.toRadians(30), // 朝向
        pitch: Cesium.Math.toRadians(-45), // 俯仰角
        roll: 0 // 翻滚角
    },
    duration: 3 // 飞行时间(秒)
});

实用技巧和示例

下面分享几个实用的Cesium功能和示例,这些在实际项目中超级有用!

加载不同类型的影像图层

Cesium支持多种影像服务:

javascript 复制代码
// 添加Bing地图影像
viewer.imageryLayers.addImageryProvider(
    new Cesium.BingMapsImageryProvider({
        url: 'https://dev.virtualearth.net',
        key: '你的Bing Maps API密钥',
        mapStyle: Cesium.BingMapsStyle.AERIAL_WITH_LABELS
    })
);

// 添加WMS服务
viewer.imageryLayers.addImageryProvider(
    new Cesium.WebMapServiceImageryProvider({
        url: 'https://某WMS服务地址',
        layers: '图层名',
        parameters: {
            format: 'image/png',
            transparent: true
        }
    })
);

添加3D建筑和城市模型

3D Tiles是Cesium的一项重要技术,用于流式加载大规模3D模型:

javascript 复制代码
// 加载3D建筑模型
const tileset = viewer.scene.primitives.add(
    new Cesium.Cesium3DTileset({
        url: Cesium.IonResource.fromAssetId(96188) // 这是纽约的3D建筑模型ID
    })
);

// 设置样式,例如根据建筑高度着色
tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ['${height} >= 300', 'color("red")'],
            ['${height} >= 200', 'color("orange")'],
            ['${height} >= 100', 'color("yellow")'],
            ['true', 'color("white")']
        ]
    }
});

绘制路径和轨迹

可以使用Entity创建动态路径:

javascript 复制代码
// 定义路径点
const positions = [];
for (let i = 0; i < 100; i++) {
    const longitude = 116.4 + Math.random() * 0.1;
    const latitude = 39.9 + Math.random() * 0.1;
    positions.push(Cesium.Cartesian3.fromDegrees(longitude, latitude, 0));
}

// 创建路径实体
const path = viewer.entities.add({
    polyline: {
        positions: positions,
        width: 5,
        material: new Cesium.PolylineGlowMaterialProperty({
            glowPower: 0.2,
            color: Cesium.Color.BLUE
        })
    }
});

// 创建沿路径移动的点
const point = viewer.entities.add({
    position: new Cesium.CallbackProperty(function(time) {
        // 计算当前时间在路径上的位置
        const seconds = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);
        const index = Math.floor(seconds * 5) % positions.length;
        return positions[index];
    }, false),
    point: {
        pixelSize: 15,
        color: Cesium.Color.RED
    }
});

// 设置时钟开始运行
viewer.clock.shouldAnimate = true;

交互事件处理

Cesium提供了丰富的事件系统,例如鼠标点击:

javascript 复制代码
// 添加鼠标点击事件处理
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(click) {
    // 将屏幕坐标转换为地球表面坐标
    const pickedObject = viewer.scene.pick(click.position);
    if (Cesium.defined(pickedObject) && pickedObject.id) {
        // 点击了某个实体
        console.log('点击了实体:', pickedObject.id);
    } else {
        // 将屏幕坐标转换为地球表面坐标
        const cartesian = viewer.scene.pickPosition(click.position);
        if (Cesium.defined(cartesian)) {
            const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
            const longitude = Cesium.Math.toDegrees(cartographic.longitude);
            const latitude = Cesium.Math.toDegrees(cartographic.latitude);
            const height = cartographic.height;
            console.log(`点击位置:经度=${longitude}, 纬度=${latitude}, 高度=${height}米`);
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

性能优化建议

使用Cesium开发大型应用时,需要注意性能问题,这里有几个实用的优化技巧:

  1. 使用Entity还是Primitive?

    • 少量对象(<1000):使用Entity,开发更简单
    • 大量对象(>1000):使用Primitive,性能更好
  2. 限制可见性

    • 使用tileset.maximumScreenSpaceError控制3D Tiles的细节级别
    • 设置entity.showprimitive.show根据距离显示或隐藏对象
  3. 使用地形和影像的分层细节(LOD)

    • 设置适当的viewer.scene.screenSpaceCameraController.maximumZoomDistance
    • 根据距离切换不同分辨率的影像
  4. 避免频繁更新位置

    • 使用viewer.scene.requestRender()而不是每帧更新
    • 对于动画,使用Cesium的时钟系统和CallbackProperty
  5. 使用BatchTable和GPU批处理

    • 对于大量相似的对象,使用BatchTable进行批处理
    • 考虑使用Cesium的BatchedInstancedFeatures

常见问题和解决方案

在使用Cesium过程中,我遇到过这些常见问题,分享给大家:

1. "terrain provider is not ready"错误

这通常是因为地形提供者还没有完全加载。解决方法是在使用地形之前先检查其就绪状态:

javascript 复制代码
Cesium.Terrain.fromWorldTerrain().readyPromise
    .then(function(terrain) {
        viewer.terrainProvider = terrain;
        // 现在可以安全地使用地形了
    });

2. 坐标转换问题

Cesium中有多种坐标系统,常见的有:

  • 经纬度坐标(度)
  • Cartesian3(笛卡尔坐标)
  • Cartographic(弧度表示的经纬度)

它们之间的转换方式:

javascript 复制代码
// 经纬度转Cartesian3
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);

// Cartesian3转经纬度
const cartographic = Cesium.Cartographic.fromCartesian(position);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;

3. 如何测量距离和面积

使用Cesium的空间计算功能:

javascript 复制代码
// 计算两点距离
const point1 = Cesium.Cartesian3.fromDegrees(116.4, 39.9);
const point2 = Cesium.Cartesian3.fromDegrees(121.5, 31.2);
const distance = Cesium.Cartesian3.distance(point1, point2); // 米

// 计算多边形面积
const positions = [
    Cesium.Cartesian3.fromDegrees(116.0, 40.0),
    Cesium.Cartesian3.fromDegrees(117.0, 40.0),
    Cesium.Cartesian3.fromDegrees(117.0, 39.0),
    Cesium.Cartesian3.fromDegrees(116.0, 39.0)
];

// 需要手动计算面积,Cesium没有直接的API
// 可以使用turf.js等库辅助计算

4. 在线和离线部署的区别

在线模式需要Cesium ion账号和互联网连接,而离线部署需要:

  • 下载并本地托管Cesium静态资源
  • 准备本地地形和影像数据
  • 配置适当的本地数据提供者
javascript 复制代码
// 使用本地地形
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
    url: './terrain'
});

// 使用本地影像
viewer.imageryLayers.addImageryProvider(
    new Cesium.TileMapServiceImageryProvider({
        url: './imagery'
    })
);

后续学习资源

如果你想深入学习Cesium,这些资源非常有用:

  1. Cesium官方文档
  2. Cesium Sandcastle示例
  3. Cesium社区论坛
  4. Cesium GitHub仓库

结语

Cesium是一个功能强大的3D地球和地图库,它让我们能够创建令人惊叹的地理可视化应用。从简单的地图展示到复杂的时空数据分析,Cesium都能胜任。

虽然刚开始学习时有一定的门槛,但一旦掌握了基本概念,你就能快速开发出专业级的地理应用。希望这篇入门教程能够帮助你迈出第一步!

最后的建议是------多看官方示例,多动手实践,遇到问题就去查官方文档和社区。Cesium的世界很大,探索起来非常有趣!

记得,地图和地理数据可视化不仅仅是技术,更是一门艺术。用Cesium,让你的数据在3D世界中活起来吧!

相关推荐
研梦非凡4 小时前
探索3D空间的视觉基础模型系列
人工智能·深度学习·神经网络·机器学习·计算机视觉·3d
71-310 小时前
C语言速成秘籍——跳转语句(goto)
c语言·笔记·学习·其他
pixelpilot11 小时前
Nimble:让SwiftObjective-C测试变得更优雅的匹配库
开发语言·其他·objective-c·swift
matrixmind111 小时前
Nivo 用React打造精美数据可视化的开源利器
其他·react.js·信息可视化·开源
CG_MAGIC1 天前
VR 太阳光参数与快速渲染
3d·vr·3dmax·vray·渲云渲染·灯光设置
私人珍藏库1 天前
[Windows] 3D软件 Blender 5.0 alpha版
windows·3d·建模
列兵阿甘1 天前
知微传感Dkam系列3D相机SDK例程篇:CSharp点云滤波
数码相机·3d
LK_071 天前
【Open3D】Open3D 可视化窗口交互控制说明
笔记·3d
老陈头聊SEO2 天前
巧用长尾关键词提升SEO效果的全方位策略解析
其他