Cesium快速入门到精通系列教程二

article/2025/8/13 12:17:15

一、添加地形与添加自定义地形

在 Cesium 1.93 中添加地形可以通过配置terrainProvider实现。Cesium 支持多种地形数据源,包括 Cesium Ion 提供的全球地形、自定义地形服务以及开源地形数据。下面介绍几种常见的添加地形的方法:

使用 Cesium Ion 全球地形服务

这是最简单的方式,需要一个 Cesium Ion 账户和访问令牌:

// 设置Cesium Ion访问令牌
Cesium.Ion.defaultAccessToken = '你的Cesium Ion令牌';// 初始化Viewer并启用全球地形
const viewer = new Cesium.Viewer('cesiumContainer', {terrainProvider: Cesium.createWorldTerrain({requestVertexNormals: true, // 启用地形光照requestWaterMask: true      // 启用水面效果}),baseLayerPicker: false, // 可选:禁用默认图层选择器
});

添加自定义地形

1、从地理空间数据云下载数据:

数据资源->公开数据->DEM 数字高程数据

2、从cesiumlab下载工具进行数据转换:

安装下载的工具,比如当前版本cesiumlab4_4.0.8.exe;

打开工具,安装以下方式设置提交即可:

 

将以上生成的瓦片本地部署,部署的方式很多种,只要保证能通过url在线访问即可:

在代码中加载:

const viewer = new Cesium.Viewer('cesiumContainer', {terrainProvider: new Cesium.CesiumTerrainProvider({url: 'http://localhost:3000', // 替换为你的服务器地址requestVertexNormals: true, // 请求法线以支持地形光照requestWaterMask: true      // 请求水掩码以支持水面效果})
});

二、相机的方向和位置

在Cesium 1.93中,相机的方向和位置控制是三维场景交互的核心。

1、相机坐标系与关键概念

1.1 相机坐标系基础

  • 位置(Position):相机在三维空间中的笛卡尔坐标(Cartesian3),以地球质心为原点。
  • 方向(Direction):相机的朝向,由视线向量(View Vector)表示,指向场景中的目标点。
  • 上方向(Up Vector):相机的 “上方” 方向,默认与地球表面垂直(Z 轴正方向)
    1. heading​​:绕Y轴旋转(正北为0°,向东为正方向)。
    2. ​​pitch​​:绕X轴旋转(-90°为俯视地面,0°为平视,正值为仰视)。
    3. ​​roll​​:绕Z轴旋转(默认0°,正值为右倾)。
  • 参考系(Reference Frame):相机运动的参考坐标系,通常为ENU(东 - 北 - 上)或ECF(地心地固坐标系)。
const orientation = {heading: Cesium.Math.toRadians(0),   // 正北pitch: Cesium.Math.toRadians(-90),   // 俯视地面roll: 0.0
};

2、相机控制的核心方法

2.1 setView:直接设置视角​​

特点​​:无动画,立即切换到目标位置和方向。

viewer.camera.setView({destination: position,  // 目标位置(Cartesian3)orientation: orientation // 方向参数
});

2.2 flyTo:动画飞行至目标​​

特点​​:支持平滑过渡,可设置飞行时长、视角偏移等。

关键参数​​:

  • duration:动画时间(秒)。
  • pitchAdjustHeight:高度超过此值时自动调整俯仰角。
viewer.camera.flyTo({destination: position,orientation: orientation,duration: 5,  // 5秒动画pitchAdjustHeight: -90  // 强制俯视地面
});

2.3 lookAt:视角锁定目标点​​

特点​​:相机位置固定,始终朝向目标点。

参数​​:target(目标点)和offset(偏移量,支持HeadingPitchRange)。

const center = Cesium.Cartesian3.fromDegrees(116.4, 39.9);
viewer.camera.lookAt(center, new Cesium.HeadingPitchRange(0, -Math.PI/2, 1000));

2.4 viewBoundingSphere:环绕目标区域​​

适用场景​​:室内或小范围模型浏览。

const boundingSphere = new Cesium.BoundingSphere(center, radius);
viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0, 0, 0));

2.5 方向控制的进阶应用

2.5.1  ​​局部坐标系转换​​

使用Transforms.eastNorthUpToFixedFrame将局部坐标转换为全局坐标系: 

const localPosition = new Cesium.Cartesian3(10, 20, 0);
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(localPosition);
const globalPosition = Cesium.Matrix4.multiplyByPoint(transform, localPosition);
2.5.2 动态方向控制​​

通过事件监听实时更新相机方向: 

viewer.scene.preRender.addEventListener(() => {const heading = viewer.camera.heading;const pitch = viewer.camera.pitch;console.log(`当前航向:${Cesium.Math.toDegrees(heading).toFixed(2)}°`);
});
2.5.3 实体跟随模式​​

使用trackedEntity让相机自动跟随移动目标: 

viewer.trackedEntity = entity;  // 实体ID或对象

2.6 常见问题与注意事项

  • 坐标系一致性​​

确保位置和方向参数在同一坐标系下(如WGS84)。若使用局部坐标,需通过变换矩阵转换。

  • 俯仰角限制​​

默认俯仰角范围为[-π/2, π/2],超出可能导致视角异常。可通过viewer.camera.pitchLimits调整。

  • ​​性能优化​​

频繁调用flyTo或setView时,建议合并连续操作,避免卡顿。

2.7 完整示例:相机环绕目标点

// 定义目标点(北京天安门)
const target = Cesium.Cartesian3.fromDegrees(116.397, 39.908, 50);// 设置相机初始位置和方向
viewer.camera.setView({destination: Cesium.Cartesian3.fromDegrees(116.397, 39.908, 1000),orientation: {heading: Cesium.Math.toRadians(0),pitch: Cesium.Math.toRadians(-30),roll: 0}
});// 启动环绕动画(每5秒绕目标一圈)
viewer.clock.onTick.addEventListener(() => {const time = Cesium.JulianDate.now(viewer.clock.currentTime);const angle = (time.secondsOfDay * 360) / 5;  // 每5秒旋转360°viewer.camera.setView({destination: Cesium.Cartesian3.fromDegrees(116.397 + 10 * Math.cos(Cesium.Math.toRadians(angle)),39.908 + 10 * Math.sin(Cesium.Math.toRadians(angle)),1000),orientation: {heading: Cesium.Math.toRadians(angle),pitch: Cesium.Math.toRadians(-30),roll: 0}});
});

2.8 相机动画与相机动态交互

 Cesium 1.93 实现镜头飞向故宫的完整示例,包含了基础的场景设置、相机飞行动画以及简单的交互控制。

<template><div id="cesiumContainer"></div><div class="controls"><button id="flyToPalaceBtn">飞向故宫</button><button id="flyToGreatWallBtn">飞向长城</button><button id="resetViewBtn">重置视角</button></div>
</template><script setup>
Cesium.Ion.defaultAccessToken = 'Cesium defaultAccessToken'
import { onMounted } from "vue";
import * as Cesium from "cesium";
import "./Widgets/widgets.css";window.CESIUM_BASE_URL = "/"; // 设置Cesium静态资源路径(public目录)onMounted(() => {// 初始化Viewerconst viewer = new Cesium.Viewer('cesiumContainer', {geocoder: false, //设置搜索框是否可见homeButton: false, // 返回初始位置键是否可见sceneModePicker: false, // 查看器选择模式选择键是否可见baseLayerPicker: false, // 图层选择键是否可见navigationHelpButton: false, // 帮助按钮是否可见animation: false, // 播放控制按钮是否可见timeline: false, // 时间轴是否可见fullscreenButton: false, // 全屏按钮是否可见terrainProvider: Cesium.createWorldTerrain()});// 故宫位置(经纬度和高度)const palacePosition = {destination: Cesium.Cartesian3.fromDegrees(116.3907917, 39.9158389, 500), // 经度、纬度、高度(米)orientation: {heading: Cesium.Math.toRadians(0.0), // 偏航角(向东)pitch: Cesium.Math.toRadians(-30.0), // 俯仰角(向下倾斜)roll: 0.0 // 翻滚角},duration: 5, // 飞行持续时间(秒)maximumHeight: 2000, // 飞行过程中最大高度(米)curveAmount: 0.5 // 飞行曲线弯曲程度(0-1)};// 长城位置(慕田峪段)const greatWallPosition = {destination: Cesium.Cartesian3.fromDegrees(116.6558, 40.4139, 500),orientation: {heading: Cesium.Math.toRadians(90.0),pitch: Cesium.Math.toRadians(-20.0),roll: 0.0},duration: 5,maximumHeight: 3000};// 初始视角const initialView = {destination: Cesium.Cartesian3.fromDegrees(116.3907917, 39.9158389, 15000),orientation: {heading: Cesium.Math.toRadians(0.0),pitch: Cesium.Math.toRadians(-30.0),roll: 0.0}};// 设置初始视角viewer.camera.setView(initialView);// 飞向故宫按钮事件document.getElementById('flyToPalaceBtn').addEventListener('click', function () {viewer.camera.flyTo(palacePosition);});// 飞向长城按钮事件document.getElementById('flyToGreatWallBtn').addEventListener('click', function () {viewer.camera.flyTo(greatWallPosition);});// 重置视角按钮事件document.getElementById('resetViewBtn').addEventListener('click', function () {viewer.camera.setView(initialView);});
})</script><style scoped>
* {margin: 0;padding: 0;
}#cesiumContainer {width: 100wh;height: 100vh;
}.controls {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);display: flex;gap: 10px;z-index: 100;
}button {padding: 8px 16px;background-color: #007BFF;color: white;border: none;border-radius: 4px;cursor: pointer;font-size: 14px;
}button:hover {background-color: #0056b3;
}
</style>


http://www.hkcw.cn/article/MCOnODSBJQ.shtml

相关文章

基于FashionMnist数据集的自监督学习(生成式自监督学习VAE算法)

目录 一&#xff0c;VAE 1.1 VAE的简介 1.2 VAE的核心思想 1.3 VAE的结构 1.4 VAE的工作原理 1.5 VAE 与传统自动编码器&#xff08;AE&#xff09;的区别 1.6 VAE 的应用场景 二&#xff0c;代码逻辑分析 2.1 整体逻辑 2.2 VAE模型 2.3 训练策略与优化 2.4 自适应学…

ESP32基础知识1:项目工程建立和烧录

ESP32基础知识1&#xff1a;项目工程建立和烧录 一、本文内容与前置知识点1. 本文内容2. 前置知识点 二、新建工程1. 工程配置2. 依照模板建立项目 三、硬件烧录1. 硬件准备2. 烧录器和ESP32连接3. 电脑端设置4. 烧录成功演示 四、参考文献 一、本文内容与前置知识点 1. 本文内…

duilib图片属性中corner属性九宫格拉伸说明

在duilib中&#xff0c;图片设置里有corner属性&#xff0c;类似于android系统里的九宫格&#xff0c;对应的分区域拉伸被称为九宫格拉伸。设置corner属性后&#xff0c;将区域分成3x3的九个区域&#xff0c;如下所示&#xff1a; 除了4个拐角区域不拉伸&#xff0c;其余5个区域…

《操作系统真相还原》——进入内核

ELF 按书上的操作来&#xff0c;在现代操作平台编译链接默认生成elf64 格式的文件&#xff0c; 很显然程序头位置发生变化&#xff0c;因为定义elf 结构的类型中有64位&#xff0c;所以我们需要将编译链接出32位格式的 gcc -m32 -c -o main.o main.c ld -m elf_i386 main.o …

笔试笔记(运维)

&#xff08;数据库&#xff0c;SQL&#xff09; limit1 随机返回其中一个聚合函数不可以嵌套使用 【^】这个里面的数据任何形式组合都没有 sql常用语句顺序&#xff1a;from-->where-->group by-->having-->select-->order by-->limit 只要其中一个表存在匹…

医疗数理范式化:从范式迁移到认知革命的深度解析

引言 在当代医疗领域,数理思维已经从辅助工具逐渐发展成为核心决策支持系统的关键组成部分。随着数字技术的迅猛发展,医疗行业正经历着前所未有的变革,而数理思维作为这一变革的核心驱动力,正在深刻重塑医疗实践的方方面面。数理思维在医疗领域的应用,本质上是将抽象的数…

golang -- slice 底层逻辑

目录 一、前言二、结构三、创建3.1 根据 make创建3.2 通过数组创建 四、内置append追加元素4.1 追加元素4.2 是否扩容4.2.1 不扩容4.2.2 扩容 总结 一、前言 前段时间学了go语言基础&#xff0c;过了一遍之后还是差很多&#xff0c;所以又结合几篇不同资料重新学习了一下相关…

Fashion-MNIST LeNet训练

前面使用线性神经网络softmax 和 多层感知机进行图像分类&#xff0c;本次我们使用LeNet 卷积神经网络进行 训练&#xff0c;期望能捕捉到图像中的图像结构信息&#xff0c;提高识别精度&#xff1a; import torch import torchvision from torchvision import transforms f…

数据库系统概论(十)SQL 嵌套查询 超详细讲解(附带例题表格对比带你一步步掌握)

数据库系统概论&#xff08;十&#xff09;SQL 嵌套查询 超详细讲解&#xff08;附带例题表格对比带你一步步掌握&#xff09; 前言一、什么是嵌套查询&#xff1f;1. 基础组成&#xff1a;查询块2. 嵌套的两种常见位置&#xff08;1&#xff09;藏在 FROM 子句里&#xff08;当…

Azure 机器学习初学者指南

Azure 机器学习初学者指南 在我们的初学者指南中探索Azure机器学习&#xff0c;了解如何设置、部署模型以及在Azure生态系统中使用AutoML & ML Studio。Azure 机器学习 &#xff08;Azure ML&#xff09; 是一项全面的云服务&#xff0c;专为机器学习项目生命周期而设计&am…

使用win11圆角指针教程

一.准备文件 win11圆角指针下载链接&#xff1a;https://wwxh.lanzoum.com/iwsZH2xqmy0d 密码&#xff1a;em 二.开始安装 1.将下载的压缩包解压&#xff08;随便存哪&#xff0c;最后可以删掉&#xff09; 右键&#xff0c;点击“全部解压缩” 点击“提取” 2.安装 选…

day16 leetcode-hot100-30(链表9)

24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 1.模拟法 思路 模拟题目要求进行两两交换&#xff0c;但有一点需要注意&#xff0c;比如交换3与4后&#xff0c;1仍然指的是3&#xff0c;这是不正确的&#xff0c;所以1指针的next也需要修改&#xff0c;所…

C语言进阶--程序的编译(预处理动作)+链接

1.程序的翻译环境和执行环境 在ANSI C标准的任何一种实现中&#xff0c;存在两种不同的环境。 第一种是翻译环境&#xff1a;将源代码转换为可执行的机器指令&#xff08;0/1&#xff09;; 第二种是执行环境&#xff1a;用于实际执行代码。 2.详解编译链接 2.1翻译环境 程…

GCA解码大脑因果网络

格兰杰因果分析&#xff08;Granger Causality Analysis,GCA&#xff09; 是一种测量脑区之间有效性连接&#xff08;effective connectivity&#xff09;的成熟方法。利用多元线性回归分析一个时间序列的过去值是否能正确预测另一个时间序列的当前值&#xff0c;可以用来描述脑…

H5S 大华SDK带图报警类型及热成像报警支持

目前很多应用都希望报警带对应的图片&#xff0c;比如控制中心在弹报警框的时候需要有一张图片让人工更快的做出判断&#xff0c;下面介绍使用大华SDK 的带图报警功能。 大华SDK支持接入设备带图报警&#xff0c;并且支持热成像通道报警&#xff0c;设置订阅事件并吧协议端口设…

(javaSE)Java数组进阶:数组初始化 数组访问 数组中的jvm 空指针异常

数组的基础 什么是数组呢? 数组指的是一种容器,可以用来存储同种数据类型的多个值 数组的初始化 初始化&#xff1a;就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。 数组初始化的两种方式&#xff1a;静态初始化&#xff0c;动态初始化 数组的静态初始化 初始化…

Java数据结构——八大排序

排序 插⼊排序希尔排序直接选择排序堆排序冒泡排序快速排序归并排序计数排序 排序的概念 排序&#xff1a;就是将一串东西&#xff0c;按照要求进行排序&#xff0c;按照递增或递减排序起来 稳定性&#xff1a;就是比如排序中有两个相同的数&#xff0c;如果排序后&#xff0c…

【Linux】Linux文件系统详解

目录 Linux系统简介 Linux常见发行版&#xff1a; Linux/windows文件系统区别 Linux文件系统各个目录用途 Linux系统核心文件 系统核心配置文件 用户与环境配置文件 系统运行与日志文件 Linux文件名颜色含义 Linux文件关键信息解析 &#x1f525;个人主页 &#x1f52…

2023年6月6级第一套第一篇

虽然&#xff0c;不重要题干定位到主句信息了&#xff0c;往下走&#xff0c;看强调什么信息看最后一句&#xff0c;优先看主干信息&#xff0c;先找谓语然后找主语和宾语&#xff0c;也是和人有关&#xff0c;后面出现的名词信息是修饰部分&#xff0c;非主干信息不看 A选项&…

Langchaine4j 流式输出 (6)

Langchaine4j 流式输出 大模型的流式输出是指大模型在生成文本或其他类型的数据时&#xff0c;不是等到整个生成过程完成后再一次性 返回所有内容&#xff0c;而是生成一部分就立即发送一部分给用户或下游系统&#xff0c;以逐步、逐块的方式返回结果。 这样&#xff0c;用户…