稀土掘金 稀土掘金

Cesium 入门

Cesium 入门

cesium, 读作[ˈsiːziəm],中文直译是化学元素铯

cesium 是一个用于显示三维地球影像的javscript开源库,它基于webgl,旨在释放3d渲染的力量。能够在web平台搭建虚拟地球以及场景展示应用。

webgl: 一个底层绘图javasctipt API集合。threejs是一个知名的webgl框架。threejs和webgl的关系类似于jquery和原生js的关系。它是一个工具库。

cesium没有采用threejs类似的工具库,是直接基于webgl来开发, cesium是对于webgl具体的应用(绘制虚拟地球),而我们在cesium搭建的虚拟地球中扩展出更为具体的应用。

接下来会介绍一个具体的例子,在东方明珠塔上方放置一个飞向兰州的飞机,然后通过这个例子穿插一些知识的讲解。 http://localhost:8080/Apps/Sandcastle/index.html?src=air.html

准备工作

  • npm install cesium
  • 引入一个cdn打包好的js脚本文件

www.cesium.com/learn/cesiu…

注意一下使用的时候需要在cesium官网上注册一个token, 因为你获取到的数据都是通过cesium.ion 这个云平台上获取的。不准确的说,cesium和cesium ion的关系类似于git和github, 或者docker和dockerhub的关系。

或者也不需要进行前面的步骤,可以直接将 github上将cesium源码clone下来,启动示例服务。cesium有很多例子并且实时修改源码看效果,是一个很好的学习方式。

把代码拷下来后运行:

npm install // 安装依赖

npm run build // 构建cesium源码

npm run build-docs // 构建cesium文档

npm run start // 启动示例服务

第一步:来绘制一个地球

const viewer = new Cesium.Viewer("cesiumContainer"); http://localhost:8080/Apps/Sandcastle/index.html

在js中一行代码即可。可见使用cesium非常的简单,但这里有几个概念需要讲解一下。 cesium类似于vue,react等一样,需要一个挂载点,即你需要把你的画面渲染在html中的哪一个dom节点。这个cesiumContainer即挂载点id。

id.png

不过你发现,其实这样写可以: const viewer = new Cesium.CesiumWidget("cesiumContainer"); http://localhost:8080/Apps/Sandcastle/index.html?src=Cesium%20Widget.html

少了哪些东西?少了界面的很多控件,那些都是dom,暂时先忽略。而cesium真正创建三维窗口,渲染页面到canvas上的,是cesiumWidget这个核心类。

cesiumWidget的主要结构(它的属性)

image.png

  • clock主要用来记录时间,因为cesium渲染出的地球是动态展示的,所以需要通过时间来绘制某一帧的内容。
  • container即刚刚讲到的挂载点,通过它可以拿到dom对象。
  • canvas则是在container上构建的Canvas类对象,通过webgl渲染的场景都绘制在这个canvas上。
  • screenSpaceEventHandler, 可以通过这个对象来监听一些屏幕上的事件,比如鼠标移动,鼠标点击等等。

注意哈,这些属性都是小写的,它们的引用都是实例。

scene对象

scene中装载了所有的图元对象,比较重要。图元对象就是cesium用来绘制对象的最小单位。在默认的实例中,都有哪些图元对象呢?显然有地球(globe),skyBox(天空盒,即后面的宇宙背景),sun(太阳),moon(月亮,不过我没找到。。),这些都是系统内置的。

另外还有两个用来由用户自行添加的图元对象的容器:primitives和groundPrimtives数组。 我们后续添加飞机模型的时候,就是将创建好的飞机模型,添加进primitives。

image-1.png

常见的图元类

上述的图元对象都由图元类进行实例化,常见的图元类有Globe,Model,Primitive,Billboards,Labels等

image-3.png

Globe地球类

通过它来实例化出地球。他需要两个东西,一个是地形高程信息,另外一个是影像图层。 影像图层,即拍摄出的很多很多地球图片。地形高程信息,即地球的每个地点的海拔高度数据。这两个数据其实都是通过云平台来实时获取的(默认是通过cesium.ion的, 但其实可以设置provider(提供者), 比如也可以通过google earth,NASA来获取地球影像信息或者地形高程信息)。注意哈,这两个数据量巨大,不可能一次性加载到位,它是懒加载的,即通过视角的位置来获取相应经纬度坐标的数据,可以通过控制台来看到这些数据,每次视角移动时,都会加载很多张图片:

image-4.png

所以绘制出地球影像,是一个个图片切片拼接上去的。 影像可以进行叠加,就像下面这个例子中,添加了两个影像图层:外层的图层设置了透明度。 http://localhost:8080/Apps/Sandcastle/index.html?src=image-cutout.html

初始情况下,地形高程信息默认为0,即渲染地球的时候是没有高度数据的。但可以通过设置terrainProvider来设置地形信息的提供方,这样绘制出的地球会更加生动(因为有了高度数据) http://localhost:8080/Apps/Sandcastle/index.html?src=Terrain.html&label=Development

Model模型类

通过它来解析引入的3d模型数据,常见的3d模型数据格式是gltf, 由一些常见的3d建模工具生成,比如3ds Max, Maya等。 gltf其实是一个json。一个json怎么描述一个模型呢?主要就是通过顶点和三角形数据。其中模型中的每一个顶点都是在一个空间直角坐标系中的一个点,再把其中相应的顶点连接起来,形成一个个三角形,就可以描述一个模型数据。

image-11.png

image-12.png

顶点数据与三角形数据

image-5.png

Primitive几何类

通过这个类来创建一些简单的几何体,比如立方体椭球体等等 http://localhost:8080/Apps/Sandcastle/index.html?src=development%2FBox.html&label=Development

Billboards/Labels

Billborads可以理解成html5的img http://localhost:8080/Apps/Sandcastle/index.html?src=development%2FBillboards.html&label=Development Labels可以理解成文字元素 http://localhost:8080/Apps/Sandcastle/index.html?src=development%2FLabels.html&label=Development

特点:

  • 这两个类创建出的图元都是始终面朝屏幕(没有贴着地形走)
  • 都是批量创建的,不能在场景中添加单独的Billboard图元(但系统里确实有这个类),都是添加的是Billborads(带了s的)
const billboards = scene.primitives.add(
    new Cesium.BillboardCollection()
  );
  billboards.add({
    image: "../images/Cesium_Logo_overlay.png", // default: undefined
    show: true, // default
    position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
    horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // default
    verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // default: CENTER
    scale: 2.0, // default: 1.0
    color: Cesium.Color.LIME, // default: WHITE
    rotation: Cesium.Math.PI_OVER_FOUR, // default: 0.0
    width: 100, // default: undefined
    height: 25, // default: undefined
  });

第二步,将飞机放入到场景中

前面带大家简单了解了一些cesiumWidget的整体结构,并且了解了常见的图元类型。现在来解决最开始提出的问题,怎么将飞机模型放入到东方明珠塔大楼上方?

那么这个过程需要经历哪些步骤呢?

1.定位东方明珠塔的位置

第一步比较简单,需要定位东方明珠塔的位置,从网上找到东方明珠塔的经纬度坐标(31.23958,121.499763)

2.根据经纬度坐标在cesium中找到这个位置

首先需要知道cesium定位位置时采用什么坐标系? 它采用的是wgs84坐标系,它是一个空间直角坐标系,原点定义为地球的质心,x轴指向赤道平面和本初子午线的交点,它是一个右手系,进而再确定出y轴指向。

image-7.png

所以,在代码中将经纬度坐标转换成wgs84坐标

  const height = 5000
  const origin = Cesium.Cartesian3.fromDegrees(
    121.499763,
    31.23958,
    height // 距离地面高度为5000m
  );
  // 可以打印出这个坐标,显然,这个单位是米
  console.log(origin) // (-1705102.1665893272, 4991709.421547006, 3582384.484603829)
  

3.设置飞机的朝向

前面我已经找到了这个位置,但是我要怎么设置模型的朝向呢?这一步相对麻烦一点 想象一下,飞机一共可以往三个方向旋转,如图:

那么,怎么设置这三个角度呢?

同样,还是需要引入一个坐标系,这个坐标系是已飞机模型的中心(这个中心是建模软件设置的)为原点,已当地的正东方向为x轴,正北方向为y轴,z轴指向宇宙,垂直于地面。这个坐标轴同样是右手系,注意在cesium里面的坐标系都是右手系。

如图:

image-8.png

有了这三个轴,便可以设置相应的角度来设置模型的朝向:

分别是:

  • yaw是围绕z轴旋转,叫做偏航角(在cesium中叫做heading)
  • pitch是围绕y轴旋转,叫做俯仰角
  • roll 围绕x轴旋转,也叫做翻滚角 在cesium中代码如下:
const heading = -156 // 顺时针方向转动为正,往逆时针转动156°大约是飞机朝向兰州的方向
const pitch = 0 // 不设置俯仰角, 默认是平的
const roll = 0 // 不设置翻滚角, 默认是平的
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
  origin,
  hpr
);
// headingPitchRollToFixedFrame是将模型位置,朝向整合到一起放入到一个4*4的矩阵中

// 然后从gltf文件中加载模型数据
model = scene.primitives.add(
  await Cesium.Model.fromGltfAsync({
    url: '../../SampleData/models/CesiumAir/Cesium_Air.glb',
    modelMatrix: modelMatrix
  })
);


为什么是4*4的矩阵?按道理来说这里的空间是3维数据,但是为什么这里是4*4的矩阵呢? 是为了方便计算。对模型做变换时,比如说对模型做缩放或者旋转变换时,实际都是可以表示成矩阵之间的乘法,但是3*3下的数据是无法用矩阵乘法表示平移的,但是当转换成齐次坐标系时(4*4),则统一都可以表示成矩阵乘法。

4.设置相机的朝向

走到这里,已经设置好了飞机的位置以及朝向。 或者更具体的说,我们设置了一个场景,这个场景中有宇宙背景,有太阳,有月亮,还有地球(这些其实没有写任何代码,是cesium自动添加上去的),当然还有一个飞机(这是我们手动添加的)。

但这里还有个问题,就是你需要设置一个眼睛(专业说法叫做camera,相机),或者说你需要定义你怎么去看这个场景。我可以去看刚刚添加的飞机模型,当然也可以去看埃及金字塔。我可以仰视飞机,当然也可以俯视飞机。

其实设定相机的位置很好理解,跟前面设定飞机模型位置的过程一摸一样。 但怎么设定相机的朝向呢,不难发现,其实也是在相机上定义旋转轴,同样也是有3个角度进行设置

image-10.png

不过区别在于,这里的x轴是指向正北方向的,也就是说初始相机是看向北边的。 来看一下代码:

    const camera = viewer.camera; // 拿到相机

    // Zoom to model

    const heading = Cesium.Math.toRadians(0); //设定偏航角
    const pitch = Cesium.Math.toRadians(0); // 设定俯仰角
    const range = 200

    // 注意,这里的center设置的是相机的焦点,我设置为飞机模型的位置,所以就体现成,镜头看向了飞机。
    camera.lookAt(
      origin,
      new Cesium.HeadingPitchRange(heading, pitch, range) 
      // 这个api就是设置刚刚的3个角度,不过这个api没有暴露出roll,因为这个设置不是很常用,但同样也可以其他api进行设置(setView)。取而代之的是距离焦点的距离,我设置距离这个飞机为200m。
    );

总结

本文一开始介绍了cesium的安装使用,然后介绍了cesiumWidget这个真正渲染出画面的这个核心类,以及cesiumWidget挂载的一些属性,其中比较重要的是scene,scene描述了场景中所有的图元对象,比如地球,飞机,太阳等等(虽然地球要比飞机要复杂很多,但是它们都是图元对象,是平行的,并不存在上下级关系,而且图元类是没有基类的。)

然后则是对把飞机放入场景的这个过程进行了描述,主要是设置了飞机的位置以及朝向,然后设置了相机的位置以及方向。

参考: Cesium快速上手(2020/02)_哔哩哔哩_bilibili

玻璃钢生产厂家玻璃钢运动雕塑报价鹰潭定制玻璃钢雕塑多少钱河北商场美陈生产公司水滴雕塑玻璃钢德宏玻璃钢花盆肇庆玻璃钢动物雕塑现货成华玻璃钢造型雕塑天水玻璃钢雕塑销售方城玻璃钢雕塑厦门园林玻璃钢雕塑热线玻璃钢龙雕塑设计价位泉山玻璃钢造型雕塑玻璃钢艺术品雕塑园沙河玻璃钢雕塑重庆砂岩玻璃钢花盆武威大型玻璃钢雕塑公司六安动物玻璃钢雕塑价格玻璃钢葡萄雕塑群雕玻璃钢雕塑商场美陈工作流程四川开业商场美陈济宁玻璃钢造型雕塑长沙水景玻璃钢景观雕塑公司玻璃钢卡通雕塑工艺福建商业商场美陈批发深圳周年庆典商场美陈制作青浦区镜面玻璃钢雕塑要多少钱庆阳彩色玻璃钢雕塑普陀区商场开业美陈大型玻璃钢雕塑工程香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化