关于cesium:CesiumJS-源码杂谈-时间与时钟系统

你晓得吗? Cesium 是元素 铯 的英文单词,而 铯原子钟 具备世界上最高的计时精度工夫,是时刻距离的意思,时刻是动态的点;而工夫就指有起止时刻的一段范畴很多利用都要有一个时钟,例如 GPS 授时、实时渲染零碎,工夫能够测量很多事物,万物静止也体现了工夫在流逝1. 工夫的“诞生”首次创立工夫是呈现在 Scene 的构造函数中: function Scene (/**/) { // ... updateFrameNumber(this, 0.0, JulianDate.now()); // ...}function updateFrameNumber(scene, frameNumber, time) { const frameState = scene._frameState; frameState.frameNumber = frameNumber; frameState.time = JulianDate.clone(time, frameState.time);}源于此,很多本人利用 CesiumJS 着色器的文章中就用 FrameState 上的 frameNumber 就近似表白了“工夫”的概念,因为在 60FPS 的屏幕上,能够通过 frameNumber / 60 粗略取得工夫值(秒),然而一旦浏览器的帧速率变动,比方 144 FPS,这个取得的工夫就会不精确。 CesiumJS 应用 JulianDate 类来示意整个程序中的工夫,它是一种地理工夫零碎,叫作“儒略”日期,它有两个成员字段,一个是自儒略第一天(公元前 4713 年 1 月 1 日)到当初的天数 dayNumber,另一个是明天曾经走过的秒数(零点起算)secondsOfDay。 注:咱们所说的公历工夫,即 GregorianDate(格里日历记法),在 CesiumJS 中也是有的,是作为 JS 原生类 Date 的高精度替代品。依据下面的 Scene 类构造函数,应用 JulianDate.now 办法,无论什么时候初始化 CesiumJS,获取的工夫值永远都是程序运行的那个时刻: ...

May 21, 2023 · 2 min · jiezi

关于cesium:Cesium中的鼠标事件

10-Cesium中的鼠标事件在Cesium中,有局部状况须要和场景进行交互,这就离不开鼠标的操作。Cesium为实现这一性能,分成了两个过程。首先,传递viewer.canvas参数实例化ScreenSpaceEventHandler类,例如实例化后的名称为handler;而后,为 handler 注册鼠标事件的监听;最初,在监听事件的回调办法中获取 event,并将其作为参数执行scene.pick 办法获取对应的选中对象。因而简略介绍一下Cesium提供的鼠标监听接口。 (1)ScreenSpaceEventHandler 图形操作事件监听。构造函数为new Cesium.ScreenSpaceEventHandler(element)。ScreenSpaceEventHandler能够监听Cesium的父容器canvas的事件。对 ScreenSpaceEventHandler 类进行实例化: const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); (2)ScreenSpaceEventType 对监听事件属性进行设置 鼠标的事件接口类型。在其官网文档里共有十五种类型,此处介绍三种罕用的事件。 鼠标左键点击事件 Cesium.ScreenSpaceEventType.LEFT_CLICK 鼠标挪动事件 Cesium.ScreenSpaceEventType.MOUSE_MOVE 鼠标滚轮事件 Cesium.ScreenSpaceEventType.WHEEL (3)setInputAction 设置要在输出事件上执行的函数。是交互事件的主体。 以鼠标左键点击事件为例 let handlerPoint = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas);handlerPoint.setInputAction(function(event) { console.log(event)}, Cesium.ScreenSpaceEventType.LEFT_CLICK);注意事项:依据不同的鼠标事件,函数的返回值也不同,须要依据具体情况进行取舍。

April 23, 2023 · 1 min · jiezi

关于cesium:Cesium中Viewer界面介绍及组件显隐

Cesium中Viewer界面介绍及组件显隐任何Cesium应用程序的根底都是Viewer,Viewer是一个带有多种性能的可交互的三位数字地球的容器。在搭建第一个示例后,咱们曾经通过以下代码初始化了一个视图窗口,看到了一个根本的数字地球。 let viewer = new Cesium.Viewer("cesiumContainer"); 默认地,场景反对鼠标交互,并且反对以下相机漫游形式: 按住鼠标左键拖拽 - 让相机在数字地球立体平移按住鼠标右键拖拽 - 放缩相机鼠标滚轮滑动 - 放缩相机按住鼠标中键拖拽 - 在以后地球的屏幕两头点,旋转相机初始化界面也默认自带了一些组件,每一个组件的形容如下: geocoder:查找地位工具,查找到之后会将镜头对准找到的地址(但实际效果体验较差),默认应用微软的Bing地图homeButton:首页地位,点击之后将视图跳转到默认视角dceneModePicker:抉择视角的模式,3D,2D,哥伦布视图(CV)baseLayerPicker:图层选择器,抉择要显示的地图服务和地形服务navigationHelpButton:导航帮忙按钮,显示默认的地图管制帮忙animation:动画器件,管制视图动画的播放速度creditsDisplay:展现商标版权和数据归属timeline:时间轴,批示以后工夫,并容许用户跳到特定的工夫fullscreenButton:全屏按钮能够通过调整Viewer中的属性来管制组件的显隐: let viewer = new Cesium.Viewer("container", { animation: false, // 暗藏动画控件 baseLayerPicker: false, // 暗藏图层抉择控件 fullscreenButton: false, // 暗藏全屏按钮 vrButton: false, // 暗藏VR按钮,默认false geocoder: true, // 暗藏地名查找控件 homeButton: false, // 暗藏Home按钮 infoBox: true, // 暗藏点击因素之后显示的信息窗口 sceneModePicker: false, // 暗藏场景模式抉择控件 selectionIndicator: false, // 显示实体对象抉择框,默认true timeline: false, // 暗藏工夫线控件 navigationHelpButton: false, // 暗藏帮忙按钮 // terrainProvider:new Cesium.createWorldTerrain(), //地形开启});viewer._cesiumWidget._creditContainer.style.display = "none"; //去除版权信息

April 22, 2023 · 1 min · jiezi

关于cesium:Cesium中Camera的常用方法

08-Cesium中Camera的罕用办法camera是viewer.scene中的属性,用来管制以后的可见域。viewer.camera 是快捷写法,拜访的是 viewer.scene.camera,所以调用时这两种写法都行。介绍三种罕用的view.carmera办法。 (1)setViewCamera依据视图地位间接定位。 const position = Cesium.Cartesian3.fromDegrees(118.923, 32.482, 1785000) //能够依据需要抉择坐标与坐标类型viewer.camera.setView({ destination: position, // 相机地位 orientation: { heading: Cesium.Math.toRadians(0), // 程度旋转 -正北方向 pitch: Cesium.Math.toRadians(-90), // 高低旋转 --仰视朝向 roll: 0 // 视口翻滚角度 }})主要参数:heading: 偏航角,默认方向为正北(0°),正角度为向东旋转,即左右点头。pitch: 俯仰角,默认角度为-90°,即朝向高空,0°为平视,正角度为仰望,负角度为仰视,即低头抬头。roll: 翻转角,默认角度为0°,正角度向右旋转,负角度向左旋转,即左右歪头。 (2)flyHome默认地位 Cesium.Camera.DEFAULT_VIEW_RECTANGLE(默认视角矩形框),视角由一个矩形组成。 Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(119.9, 30.7501282784158, 121.33, 31.9645982738191);// 将相机飞到主视图,即默认矩形框区域。let duration = 2;viewer.camera.flyHome(duration)在 Cesium.Rectangle.fromDegrees()中,传入的四个参数别离为最西边坐标点的经度,最南边右边点的纬度,最东边坐标点的经度,最南边坐标点的维度,是矩形框四个坐标点的汇合。duration示意航行的持续时间,能够不传。默认值为Cesium依据须要行驶的间隔来计算航行持续时间。 (3)flyTo将相机从以后地位航行挪动到新地位。 // 1. 飞到自上而下视图的地位(垂直视角)viewer.camera.flyTo({ destination : Cesium.Cartesian3.fromDegrees(118.923, 32.482, 15000.0)});// 2. 飞到自上而下视图的矩形(垂直视角)viewer.camera.flyTo({ destination : Cesium.Rectangle.fromDegrees(119.9, 30.7501282784158, 121.33, 31.9645982738191)});// 3.应用航向、俯仰和滚转飞到一个方位.viewer.camera.flyTo({ destination : Cesium.Cartesian3.fromDegrees(118.923, 32.482, 5000.0), orientation : { heading : Cesium.Math.toRadians(175.0), pitch : Cesium.Math.toRadians(-35.0), roll : 0.0 }});(4)lookAt场景视角锁定,拖动视图次要以小球视角进行盘绕查看。应用指标和偏移量设置相机地位和方向。 ...

April 22, 2023 · 1 min · jiezi

关于cesium:Cesium加载广告牌二

Cesium加载广告牌(二)在上一篇中曾经增加了增加了广告牌实体,如果要获取更好的显示成果和其余需要,须要进行更多的设置。这里再介绍一些广告牌的罕用属性。 horizontalOrigin:广告牌绝对原点的程度地位。有三种属性:Cesium.HorizontalOrigin.CENTER,Cesium.HorizontalOrigin.LEFT,Cesium.HorizontalOrigin.RIGHT。留神这里必须大写。 verticalOrigin:广告牌绝对原点的垂直地位。有四种属性:Cesium.VerticalOrigin.CENTER,Cesium.VerticalOrigin.BOTTOM,Cesium.VerticalOrigin.BASELINE,Cesium.VerticalOrigin.TOP scale:广告牌的尺寸。是Number类型,默认值为1。 pixelOffset:广告牌的像素偏移量,是Cartesian2类型。 通过前三种属性,能够对广告牌进行地位和大小方面的微调,而不必批改广告牌的以后地位。如果须要进行更近一步的自定义地位,能够应用pixelOffset。示例如下: let bill = new Cesium.Entity({ position: new Cesium.Cartesian3.fromDegrees(120.62521517, 31.42803100), billboard: { image: "./img/laboratory.png", horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, scale: 1, pixelOffset: new Cesium.Cartesian2(0, -70),//留神这里须要应用Cartesian2 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }})如果须要更贴近事实,须要实现近大远小的成果,须要设置另一个重要属性:scaleByDistance。字面意思是追随间隔的尺寸。这个属性来实现依据摄像机的间隔扭转实体的scale(缩放比)。scaleByDistance的类型为NearFarScalar,在Cesium中为new Cesium.NearFarScalar(near, nearValue, far, farValue)。这里的四个参数类型均是Number。以new Cesium.NearFarScalar(30000, 1, 45000, 0.4)为例,含意为含意就是在摄像头和Billboard之间的间隔在30000-45000之间的时候,Billboard的Scale比例依照1->0之间的插值来缩放。当摄像头和Billboard之间间隔小于30000的时候,就依照30000时候的值1解决(这里如果不是1,而是0.5,那小于30000时候的比例就是0.5了)。而当大于45000的时候,就会依照0.4(其实就是8000对应的比例值)缩放。 let bill = new Cesium.Entity({ position: new Cesium.Cartesian3.fromDegrees(120.62521517, 31.42803100), billboard: { image: "./img/laboratory.png", horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, scale: 1, scaleByDistance:new Cesium.NearFarScalar(30000, 1, 45000, 0.4), pixelOffset: new Cesium.Cartesian2(0, -70),//留神这里须要应用Cartesian2 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }})

April 22, 2023 · 1 min · jiezi

关于cesium:Cesium加载广告牌一

Cesium加载广告牌(一)在Cesium开发中须要加载图标等操作,这时候就须要应用Cesium中增加广告牌的性能,这里须要用到一个很重要的属性办法Entity()。在官网文档中,Entity的解释为:将多种形式的可视化实体聚合到单个高级对象中。它们能够手动创立并增加到Viewer实体中,也能够由数据源(如CzmlDataSource和GeoJsonDataSource)生成,是实体的汇合。Entity蕴含很多的属性id、name、availability、show、description、position、orientation、viewFrom、parent等其余示意entity类型。此处以billboard为例,实现增加广告牌的性能。 总的来说,增加广告牌实体分为三步。 申明一个Entity对象。let bill = new Cesium.Entity({})在对象中增加实体须要显示的地位。let bill = new Cesium.Entity({ position: new Cesium.Cartesian3.fromDegrees(119.78542186676341, 29.173544144850784), })在对象中增加须要显示的实体类型。let bill = new Cesium.Entity({ position: new Cesium.Cartesian3.fromDegrees(119.78542186676341, 29.173544144850784), billboard: { image: "./img/laboratory.png", }})这样就曾经增加了一个繁难的广告牌。然而这样的广告牌显示成果并不好,广告牌也只有一半显示在地上。因而须要对广告牌进行其余属性的设置。首先让广告牌齐全显示在高空。这里能够给显示的地位提供一个高度。 let bill = new Cesium.Entity({ position: new Cesium.Cartesian3.fromDegrees(119.78542186676341, 29.173544144850784,100), billboard: { image: "./img/laboratory.png", }})然而,应用着用办法须要依据广告牌的大小实时调整所给的高度,并不利于开发,因而除非有需要须要广告牌浮空,所以并不举荐此办法。因而咱们应用另一种办法让广告牌贴地显示。这样一来,就会让广告牌显示在地形上,不会飘在地面,或者掉在地形的下边 heightReference:广告牌的绝对地位,有三种属性:NONE,CLAMP_TO_GROUND,RELATIVE_TO_GROUND disableDepthTestDistance:禁用深度检测的相机间隔,是Number类型 let bill = new Cesium.Entity({ position: new Cesium.Cartesian3.fromDegrees(119.78542186676341, 29.173544144850784), billboard: { image: "./img/laboratory.png", heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }})这样一来图标就能够实现广告牌的贴地解决,设置实现贴地属性。

April 21, 2023 · 1 min · jiezi

关于cesium:Cesium本地文档部署与第一个实例

Cesium本地文档部署与第一个实例(1)本地文档与示例部署 Cesium最新版本下载地址:https://cesium.com/downloads/,本次教程用的1.86版本的Cesium,如果以后版本较高,可点击Previous releases找到1.86版本的Cesium下载。下载之后进行解压,解压后的目录如下所示。 ├── Apps Cesium具体的范例程序。├── Buidld release包,打包后的库文件(压缩和未压缩)、SDK文档 ├── Source Cesium源码├── Specs Cesium的主动话单元测试,采纳Jasmine框架,能够实现自动化测试以及接口覆盖率等统计成果 ├── ThirdParty 内部依赖库,不同于Cesium的第三方库 ├── idnex.html Web导航首页├── server.cjs 基于node.js的web服务利用├── package.json node包管理器├── gulpfile.js 打包脚本用vscode关上解压后的文件夹,右击跟门路下的index.html,选“Open with Live Server”。这样就能够浏览官网文档与官网示例。 Document :残缺的API文档和参考。Sandcastle:Cesium的实时代码编辑器和示例库。浏览突出显示Cesium API个性的示例,并在web浏览器中编辑和运行它们。在Sandcastle中创立的应用程序能够保留和下载。Cesium ion:Cesium在线资源-地形(createWorldTerrain)、影像(createWorldImagery/IonImageryProvider)、OSM(createOsmBuildings)、点云(IonResource.fromAssetId)、3DTiles等Local links:Cesium本地资源链接,文档、示例、单元测试等External links:Cesium内部资源链接,社区、博客、GitHub等Cesium ion:Cesium在线资源-地形(createWorldTerrain)、影像(createWorldImagery/IonImageryProvider)、OSM(createOsmBuildings)、点云(IonResource.fromAssetId)、3DTiles等Local links:Cesium本地资源链接,文档、示例、单元测试等External links:Cesium内部资源链接,社区、博客、GitHub等(2)第一个实例搭建 通过在html文件中援用cesium比较简单,新建文件夹(examples),将下面的Build文件夹(只拷贝外面的Cesium)拷贝到examples中,在examples根门路下创立html文件,代码如下: <!DOCTYPE html><head> <title>Hello World</title> <script src="./Cesium/Cesium.js"></script> <link href="./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> var viewer = new Cesium.Viewer("cesiumContainer");</script></body>

April 20, 2023 · 1 min · jiezi

关于cesium:Cesium中的坐标类型及转换

06-Cesium中的坐标类型及转换1、屏幕坐标屏幕坐标是立体直角坐标系,是二维笛卡尔坐标系。Cesium中应用Cartesian2来形容屏幕坐标系构造函数是new Cesium.Cartesian2(x, y)。具体是鼠标点击地位间隔canvas左上角的像素值。屏幕左上角为原点(0.0),屏幕程度方向为X轴,向右为正,垂直方向为Y轴,向下为正。 let handlerPoint = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas); handlerPoint.setInputAction(function(event) { console.log(event) //打印出的就是屏幕坐标 }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);2、笛卡尔空间直角坐标以空间中O点为原点,建设三条两两垂直的数轴;X轴(横坐标)、Y轴(纵坐标)、Z轴(竖坐标),建设了空间直角坐标系0—XYZ。 笛卡儿空间直角坐标的原点就是椭球的核心。构造函数是new Cesium.Cartesian3(x,y,z),这里的Cartesian3外面的下x,y,z即为笛卡儿坐标系三个坐标轴方向上的重量。 3、地理坐标首先将地球形象成一个规定的迫近原始天然地球表面的椭球体,称为参考椭 球体,而后在参考椭球体上定义系列的经线 和纬线形成经纬网。须要阐明的是经纬天文坐标系不是立体坐标系,因为度不是规范的长度单位,不可用其间接量测长度和面积。基于椭球体示意空间点的地位采纳三个参数:大地经度、大地纬度、大地高。 大地经度:参考椭球面上某点的大地子午面与本初子午面间的两面角。向东为正,向西为负。 大地纬度:参考椭球面上某点的法线与赤道立体的夹角。向北为正,向南为负。 大地高:指某点沿法线方向到参考椭球面的间隔。 不同的椭球体大小、定位与定向决定了不同的坐标零碎。 以WGS-84为例,WGS-84是为美国全球定位系统(GPS)的应用而建设的坐标零碎,坐标原点为地球质心,其地心空间直角坐标系的Z轴指向BIH 1984.0定义的协定地球极(CTP)方向。X轴指向BIH1984.0定义的零子午面和CTP赤道的交点。Y轴与Z轴、X轴垂直形成右手坐标系。经度范畴为[-180°,180°],纬度范畴为[- 90°,90°]。WGS-84是目前利用范畴最为宽泛的天文坐标系,通常国外通感影像均采纳WGS-84。Cesium中定义Cartographic ,用new Cesium.Cartographic(longitude,latitude,height)来形容地理坐标,这里longitude、latitude都是弧度坐标值。 4、经纬度坐标经度:参考椭球面上某点的大地子午面与本初子午面间的两面角。东正西负。纬度:参考椭球面上某点的法线与赤道立体的夹角。北正南负。 Cesium中的坐标转换1、经纬度(Degrees)与笛卡尔空间坐标(Cartesian3)互相转换经纬度转换为笛卡尔空间坐标let point= Cesium.Cartesian3.fromDegrees(longitude,latitude,height) //height能够不传笛卡尔空间坐标转换为经纬度let cartorgraphic = Cesium.Cartographic.fromCartesian(cartesian3);2、经纬度(Cartographic)和地理坐标(Degrees)互相转换经纬度转地理坐标let point =Cesium.Math.toRadians(degrees)地理坐标转经纬度let point =Cesium.Math.toDegrees(radians)3、屏幕坐标(Cartesian2)和笛卡尔空间直角坐标(Cartesian3)互相转换屏幕坐标转笛卡尔空间直角坐标(1)蕴含了地形、歪斜摄影测量模型等其余三维模型的坐标 var cartesian3= viewer.scene.pickPosition(cartesian2);(2)地形在内,然而不包含歪斜摄影测量模型等其余三维模型的坐标 var cartesian3=viewer.scene.globe.pick(viewer.camera.getPickRay(cartesian2),viewer.scene);(3)不蕴含地形、歪斜摄影测量模型等其余三维模型的坐标 var cartesian3= viewer.scene.camera.pickEllipsoid(cartesian2);笛卡尔空间直角坐标转屏幕坐标let c2=Cesium.SceneTransfroms.wgs84ToWindowCoordinates(cartesian3);

April 20, 2023 · 1 min · jiezi

关于cesium:Cesium的四种点击拾取方法

Cesium的四种点击拾取办法1、viewer.scene.pick()通过坐标地位,拾取实体(Entity),图元(Primitive),3DTiles对象,返回的是scene中指定地位最上层的对象。例如点击获取 Entity的pick对象,通过pick.id能够拾取以后的entity对象。拾取后,能够用于扭转对象的属性参数,如色彩,图片等。 注意事项:只能获取一个对象,并且是最顶部的对象。如果拾取点没有对象,则会返回undefined let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//解决用户输出事件handler.setInputAction(function (event) { // 设置左键点击事件 let pick = viewer.scene.pick(event.position); // 获取 pick 拾取对象 if (Cesium.defined(pick)) { // 判断是否获取到了 pick pick.id.billboard.image = "......" // 批改拾取到的entity的款式 }}, Cesium.ScreenSpaceEventType.LEFT_CLICK);2、viewer.scene.globe.pick()返回一个射线(ray)和地球表面的一个交点的Cartesian3坐标。此办法个别用于获取加载地形后的经纬度和高程,不包含模型、歪斜摄影等外表高度。 注意事项:最好开启深度检测(viewer.scene.globe.depthTestAgainstTerrain = true) let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function (event) { let ray = viewer.camera.getPickRay(event.position);//获取一条射线 let position = viewer.scene.globe.pick(ray, viewer.scene); console.log("以后拾取的坐标:", position);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);3、viewer.scene.camera.pickEllipsoid()返回相机视角下鼠标点击的对应椭球面地位。接管屏幕坐标,返回Cartesian3坐标。实用裸球外表的选取,是基于数学模型的椭圆球体。 注意事项:在有地形的状况下误差较大,在应用时须要敞开深度测试。 let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function (event) { let position = viewer.scene.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid); console.log("点击拾取的坐标:", position);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);4、viewer.scene.pickPosition()拾取对应地位的Cartesian3,实用于模型外表地位的选取,拾取三维物体的坐标等。 ...

April 20, 2023 · 1 min · jiezi

关于cesium:CesiumJS-源码杂谈-从光到-Uniform

之前对实时渲染(RealTimeRendering)的殿堂就非常向往,也有简略理解过实时渲染中的光,无奈始终没能零碎学习。鉴于笔者曾经有一点 CesiumJS 源码根底,所以就抽了一个周末跟了跟 CesiumJS 中的光照初步,在简略的代码追踪后,发现想零碎学习光照材质,依然是须要 RTR 常识的,这次仅仅理解了光在 CesiumJS 底层中是如何从 API 传递到 WebGL 着色器中去的,为之后深入研究打下基础。 1. 有什么光CesiumJS 反对的光的类型比拟少,默认场景光就一个太阳光: // Scene 类构造函数中this.light = new SunLight();从下面这代码可知,CesiumJS 目前场景中只反对退出一个光源。 查阅 API,可得悉除了 SubLight 之外,还有一个 DirectionalLight,即方向光。 官网示例代码《Lighting》中就应用了方向光来模仿手电筒成果(flashLight)、月光成果(moonLight)、自定义光成果。 方向光比太阳光多进去一个必选的方向属性: const flashLight = new DirectionalLight({ direction: scene.camera.directionWC // 每帧都不一样,手电筒始终沿着相机眼帘照耀})这个 direction 属性是一个单位向量即可(模长是 1)。 说起来归一化、规范化、标准化如同都能在网上找到与单位向量相似的意思,都是向量除以模长。可见,CesiumJS 并没有内置点光源、聚光灯,须要本人写着色过程(请参考 Primitive API 或 CustomShader API)。 2. 光如何转换成 Uniform 以及何时被调用既然 CesiumJS 反对的光只有一个,那么考察起来就简略了。先给论断: 光是作为 Uniform 值传递到着色器中的。 先查分明光是如何从 Scene.light 转至 Renderer 中的 uniform 的。 2.1. 对立值状态对象(UniformState)在 Scene 渲染一帧的过程中,简直就在最顶部,Scene.js 模块内的函数 render 就每帧更新着 Context 对象的 uniformState 属性: ...

April 16, 2023 · 6 min · jiezi

关于cesium:教程-在-Vue3Ts-中引入-CesiumJS-的最佳实践2023

这篇如果 Vue 和 CesiumJS 不产生史诗级的变动,应该不会再有后文了。次要是这类文章没什么养分。 这篇次要修改上篇 https://segmentfault.com/a/1190000042385877 中一些插件的变动,并降级开发服务器的版本。 心急的敌人拉到文末,有示例工程链接下载。1. 本篇适用范围与目标1.1. 适用范围严格应用 Vue3 + TypeScript 的前端我的项目,包管理器默认应用 pnpm构建工具应用 Vite4应用原生 CesiumJS 依赖做利用开发客户端渲染,因为我不太熟悉 Vue 的服务端渲染,有本篇的介绍后,相熟 SSR 的读者能够本人接入单页利用,多页利用也能够参考此法鉴于国内应用 CesiumJS 的比例大多数为利用开发(粗话即“APICaller”),而非扩大开发(基于源码作新性能封装、打包),所以我默认读者应用 CesiumJS 是通过 npmjs 网站(或镜像站)拉取的依赖,即: pnpm add cesium@latest有想批改源码再本人打包的读者,我感觉应该去看我的源码系列博客。 1.2. 目标在 Vue3 工程中引入 CesiumJS 的最佳形式,并引出地图组件封装的简略教训两则。 这篇文章更偏向于给读者一些原理,而不是提供一套开箱即用的工具,有能力的读者能够依据这篇文章的原理,联合 Vite 或其它打包工具的 API,写一个专属插件。 2. 牛刀小试 - 先看到地球如果没有疾速看到 3D 虚构地球,我感觉心急的敌人会心急(废话)。 第 2 节不须要晓得原理,原理和最佳实际请往下浏览 3、4、5 节。 2.1. 创立 Vue3 - TypeScript 工程并装置 cesium如果你没有命令行根底,也不懂什么是 NodeJS、npm,不晓得 node-package 是什么货色,倡议先补补 NodeJS 为根底的前端工具链常识。 间接上命令行(要联网,配好你的 npm 源),请在任意你不便的中央运行: pnpm create vite输出你想要的手动抉择 Vue、TypeScript 的模板即可,而后进入工程文件夹,我的工程文件夹叫作 v3ts-cesium-2023,所以我接下来要装置 CesiumJS: ...

April 9, 2023 · 9 min · jiezi

关于cesium:记录一次获取czml卫星轨道数据

背景:本次需要基于实现卫星模型扫描地球的业务。技术栈采纳:cesium 1.103.0htmlczml 记录:1.卫星轨道数据获取地址:https://www.space-track.org/#catalog我这里抉择获取fengyun的数据,能够失去一个TLE格局的两行数据 2.卫星轨道数据通用转换因为有了tle数据,这里也抉择去用sgp4来将数据转换成czml格式文件。 #!/usr/bin/python# -*- coding:utf8 -*-"""本脚本依据TLE文件生成每颗卫星的CMZL文件,用于前端js应用Cesium显示卫星轨道"""# sgp4算法依据二行星历计算每个工夫点卫星的地位from sgp4.earth_gravity import wgs84from sgp4.io import twoline2rvimport datetimeimport json# 按行读取北斗两行星历文件# 每三行标识一个卫星,格局如下:# FENGYUN 1A# 1 19467U 88080A 23086.12932362 -.00000103 00000-0 -36906-4 0 9992# 2 19467 99.1890 121.7932 0014370 10.7878 349.3593 14.03214030768865# 星历下载地址:http://celestrak.com/with open('fengyun.txt', 'r') as f: data_lines = f.read().split('\n')#TLE每颗卫星数据必须三行:第一行名称,后两行数据"# 应用字典的数组(json文件)保留每颗卫星的轨道六根数orbit_info = {}# 每三行一组,遍历所有卫星for j in range(len(data_lines) // 3): # 第一行名字,后两行数据 # 数据具体阐明:http://celestrak.com/columns/v04n03/ name = data_lines[j * 3].strip() line1 = data_lines[1 + j * 3] line2 = data_lines[2 + j * 3] # 写轨道六根数到json文件 # print("卫星轨道倾斜角", line2[8:16], "度") # print("升交点赤经", line2[17:25], "度") # print("偏心率", line2[26:33]) # print("近地点角距", line2[34: 42], "度") # print("平近点角", line2[43:51], "度") # print("均匀静止(每天绕地球圈数)", line2[52:63]) orbit_info.update({ name: { 'Inclination': line2[8:16], 'Right Ascension of the Ascending Node'.replace(' ', '_'): line2[17:25], 'Eccentricity': line2[26:33], 'Argument of Perigee'.replace(' ', '_'): line2[34: 42], 'Mean Anomaly'.replace(' ', '_'): line2[43:51], 'Mean Motion'.replace(' ', '_'): line2[52:63] } }) # 卫星每转1°所经验的工夫(单位:秒) gap = 1. / float(line2[52:63]) * 24 * 60 * 60 / 360 # 调用sgp4算法计算星历每个时刻的地位 satellite = twoline2rv(line1, line2, wgs84) assert satellite.error == 0 # 记录以后工夫,并在循环中计算出一个周期后的工夫 # 用于在CZML文件中指定interval now_time = datetime.datetime.now() next_time = datetime.datetime.now() # 保留每1°变动后卫星的地位(x, y, z):示意具体地心的间隔(单位:km) position_list = [] # 循环一圈 # 每次距离gap秒 nums = 361 for i in range(nums): # next_time示意每个地位对应的工夫点 next_time = now_time + datetime.timedelta(seconds=gap * (i + 1)) # 示意为字典,不便propagate函数的计算 next_time_str = next_time.strftime('%Y %m %d %H %M %S').split(' ') next_time_str = [int(v) for v in next_time_str] time_key = ['year', 'month', 'day', 'hour', 'minute', 'second'] time_map = dict(zip(time_key, next_time_str)) # 调用sgp4库的propagate函数计算对应时刻的地位 position, velocity = satellite.propagate( year=time_map['year'], month=time_map['month'], day=time_map['day'], hour=time_map['hour'], minute=time_map['minute'], second=time_map['second'] ) # The position vector measures the satellite position in kilometers from the center of the earth. # CZML文件中position的格局为:(time, x, y, z, time, x, y, z...) position_list.append(next_time.isoformat()) position_list.append(position[0] * 1000) position_list.append(position[1] * 1000) position_list.append(position[2] * 1000) # 格式化为ISO工夫规范格局 begin = str(now_time.isoformat()) end = str((next_time + datetime.timedelta(seconds=gap)).isoformat()) # Write the CZML document to a file filename = "D:/test/{}.czml".format(name) # 初始化CZML # CZML实际上是JSON文件,JSON文件就是字典数组 # 所以应用字典数据结构示意每个卫星 doc = [] # 定义头部 header = { # id和version为固定格局 'id': "document", "version": "1.0", 'name': name, "clock": { # interval为无效工夫,currentTime示意起始点,multiplier示意时钟速度 "interval": '{}/{}'.format(begin, end), "currentTime": begin, "multiplier": gap } } doc.append(header) # 定义主体 body = { "id": "satellites/{}".format(name), "availability": '{}/{}'.format(begin, end), "label": { # 应用label显示卫星名字 "font": "11pt Lucida Console", "outlineWidth": 2, "outlineColor": {"rgba": [0, 0, 0, 255]}, "horizontalOrigin": "LEFT", "pixelOffset": {"cartesian2": [12, 0]}, "fillColor": {"rgba": [213, 255, 0, 255]}, "text": name }, "path": { # path定义轨道的款式 "material": { "polyline": { "color": { "rgba": [255, 0, 255, 255] } } }, "width": 1, "resolution": 120 }, "billboard": { # 卫星的图标,应用base64编码表示图片 "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADJSURBVDhPnZHRDcMgEEMZjVEYpaNklIzSEfLfD4qNnXAJSFWfhO7w2Zc0Tf9QG2rXrEzSUeZLOGm47WoH95x3Hl3jEgilvDgsOQUTqsNl68ezEwn1vae6lceSEEYvvWNT/Rxc4CXQNGadho1NXoJ+9iaqc2xi2xbt23PJCDIB6TQjOC6Bho/sDy3fBQT8PrVhibU7yBFcEPaRxOoeTwbwByCOYf9VGp1BYI1BA+EeHhmfzKbBoJEQwn1yzUZtyspIQUha85MpkNIXB7GizqDEECsAAAAASUVORK5CYII=", "scale": 1.5 }, "position": { # cartesian的格局:(time, x, y, z, time, x, y, z...) "referenceFrame": "FIXED", # 能够取FIXED和INERTIAL示意固定和惯性参考系 # 插值填补轨道 "interpolationDegree": 5, "interpolationAlgorithm": "LAGRANGE", "epoch": begin, "cartesian": position_list } } # 在body中增加position doc.append(body) # 应用JSON写CZML文件 with open(filename, 'w') as f: json.dump(doc, f)原创作者地址:https://segmentfault.com/u/yourena_c3.cesium加载卫星轨道数据 ...

March 27, 2023 · 3 min · jiezi

关于cesium:CesiumJS-PrimitiveAPI-高级着色入门-从参数化几何与-Fabric-材质到着色器-下篇

书接上文。 https://segmentfault.com/a/11... 3. 应用 GLSL 着色器明确一个定义,在 Primitive API 中利用着色器,实际上是给 Appearance 的 vertexShaderSource、fragmentShaderSource 或 Material 中的 fabric.source 设置着色器代码,它们所能管制的层级不太一样。然而他们的独特目标都是为了 Geometry 服务的,它们会随着 CesiumJS 的每帧 update 过程,创立 ShaderProgram,创立 DrawCommand,最终去到 WebGL 的底层渲染中。 3.1. 为 Fabric 材质增加自定义着色代码 - Fabric 材质的实质有了之前的 fabric.uniforms、fabric.materials、fabric.components 根底,你可能急不可待想写自定义着色器代码了。须要晓得的一点是,有了 fabric.source,就不兼容 fabric.components 了,只能二选一。 对于 fabric.uniforms,它的所有键名都能够在着色器代码中作为 GLSL Uniform 变量应用;对于 fabric.materials,它的所有键名都能够在着色器代码中作为 GLSL 变量应用,也就是一个计算实现的 czm_material 构造体变量。 编写 fabric.source,实际上就是写一个函数,它必须返回一个 czm_material 构造体,且输出一些特定的、以后片元的信息: czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); // ... 一系列解决 return material;}czm_material 曾经在之前提及过了,它蕴含了实时渲染所需的一些根本材质参数。而 materialInput 这个变量,它是 czm_materialInput 类型的构造体,定义如下: ...

February 13, 2023 · 5 min · jiezi

关于cesium:CesiumJS-PrimitiveAPI-高级着色入门-从参数化几何与-Fabric-材质到着色器-上篇

Primitive API 还包含 Appearance API、Geometry API 两个次要局部,是 CesiumJS 挡在原生 WebGL 接口之前的最底层图形封装接口(公开的),不公开的最底层接口是 DrawCommand 为主的 Renderer API,DC 对实时渲染管线的技术要求略高,可定制性也高,这篇还是以 Primitive API 为侧重点。 0. 根底0.1. 坐标系根底这里的“坐标系”特指 WebGL 图形渲染的坐标系。Primitive API 收到的几何数据,默认没有任何坐标系(即最根本的空间直角坐标),想要挪动到地表感兴趣的中央,须要借助 ENU 转换矩阵,或者把几何顶点的坐标间接设为 EPSG:4978 坐标(即所谓艰深的“世界坐标”)。 ENU 转换矩阵,用道家八卦的说法相似“定中宫”。它能将坐标转换到这样一个 ENU 地表部分坐标系上: 指定一处地表点(经纬度)为坐标原点以贴地正东方(ENU 中的 E)为正 X 轴以贴地正北方(ENU 中的 N)为正 Y 轴以地心到坐标原点的方向(即 ENU 中的 U,up)为正 Z 轴这样一个 ENU 坐标系上的部分坐标左乘 ENU 转换矩阵后,就能失去规范的 EPSG:4978 世界坐标。 GIS 中的投影坐标、经纬坐标不太实用,须要转换。 0.2. 合并批次尽管 WebGL 反对实例绘制技术,然而 Primitive API 缩小绘制调用并不是通过这个思路来的,而是尽可能地把 Vertex 数据合并,这个叫做 Batch,也就是“合并批次(并批)”。 在 CesiumJS 的 API 文档中能看到 new Primitive() 时,能够传递一个 GeometryInstance 或者 GeometryInstance 数组,而 GeometryInstance 对象又能复用具体的某个Geometry 对象,仅在几何的变换位置(通过矩阵表白)、顶点属性(Vertex Attribute)上做差异化。 ...

February 12, 2023 · 5 min · jiezi

关于cesium:Cesium-for-Unreal加载倾斜摄影

本文介绍UE4中通过Cesium插架加载本地歪斜摄影模型。Cesium for Unreal插件运行在UE环境何总运行Cesium,这样不便做一个GIS利用。 装置Cesium for Unreal插件在UE 空幻商城中,搜寻 “Cesium for Unreal”, 而后下载插件,下载实现后,能够点击装置到引擎: 能够装置到引擎,须要UE 4.26以上,笔者应用4.27版本,也能够用于UE5. 启用插件关上UE编辑器,创立一个我的项目,点击菜单: 编辑->插件,搜寻 Cesium for Unreal 点击启用。 启用之后可能须要重启 增加Cesium SunSkyCesium SunSky扩大了UE自身的SunSky,针对Cesium场景做了优化。 无关细节此处不具体阐明。 增加Dynamic Pawn DynamicPawn 是插件定制的基于Cesium场景的一个Pawn对象,赋予了基于地球的静止形式,此处也不具体阐明。实际上DynamicPawn不是必须的,也能够本人写一个Pawn 类来进行操作。然而DynamicPawn能够进行碰撞检测,让镜头总是在地球(或者歪斜摄影的外表静止),如果是挺大场景,可能这一点比拟重要。 对于较小场景,能够本人进行Pawn类的编写适宜本人的操作习惯。 增加歪斜摄影首先增加一个Blank 3D Tiles Tileset 到场景中,插件将主动增加Cesium Georeference、CesiumCameraManager、CesiumCreditSystemBPM等其它三个控件(如果原先没有)点击该对象,在该对象的详情页面设置加载的歪斜摄影门路, 在【细节】面板中,查找“Cesium”类别。 Source能够填写歪斜摄影的起源。起源能够是Cesium ion,也能够From Url。 如果须要应用Cesium ion的线上数据,能够登录Cesium ion账户。通过点击【Add】按钮,弹出【Cesium ion Assets】选项卡,外部列表数据与线上Cesium ion账户内【My Assets】选项卡中的数据一样。因为Cesium ion数据服务器在国外,思考到数据应用的安全性以及带宽流量,本文次要实际加载本地部署数据。 本地部署的时候,source抉择From Url。而From Url又能够是本地格局和网络格局。(本地格局:file:///C://tileset.json。网络URL地址格局:http:///tileset.json。) 比方笔者的案例中,应用本地文件加载,输出如下所示: 更改CesiumGeoreference定位(解决看不到)CesiumGeoreference用于设置坐标系的原点。鼠标抉择增加的3d Tile模型,按F建聚焦该对象,而后,抉择CesiumGeoreference对象,点击按钮“Place CesiumGeoreference Origin here”能够把原点定位到加载的模型处。 须要留神的一个选项是 “Keep World Origin Near Camera”,如果启用改选项,在运行态下,世界坐标原点会随着镜头的变动而变动,从而导致所有的actor(非Geo对象)的坐标都产生变动。 个别倡议在小场景下,敞开次选项。 该选项的目标是在大场景下,防止对象的坐标值很大,超过UE能够可能存储的精度。 ...

January 7, 2023 · 1 min · jiezi

关于cesium:CesiumJS-技术博客glTF-模型Model加载新架构

原文:https://cesium.com/blog/2022/...CesiumJS 和 glTF 之间有一段很长的单干关系。在 2012 年,CesiumJS 就实现了一个 glTF 加载器,是最早的一批加载器了,过后的 glTF 叫做“WebGLTF”。 这十年间,产生了很多事件。glTF 1.0 标准公布、glTF 1.0 的嵌入式着色器演进成 glTF 2.0 的 PBR 材质,glTF 的社区扩大也在蓬勃成长。最近公布的 下一代 3DTiles 间接应用了 glTF,并容许在顶点粒度下来编码属性元数据。 这么多年教训积攒下来,官网团队曾经知悉了社区在实践中是如何应用 glTF 和 3DTiles 的,当初是时候把积攒变现布局将来了。 为了实现一个更强的加载器,须要有一套残缺的设计,设计指标如下: 将 glTF 的 加载 和模型的 渲染 解耦反对逐顶点粒度的属性元数据反对自定义着色器,并且在着色器的拼接上要做到可扩大缓存纹理对象,当纹理在不同的模型间共享时,升高内存占用与 3DTiles 中的其它瓦片格局(例如 pnts)建设更清晰的结合点进步或至多不能低于原有的加载、渲染性能尽管在公共 API 的调用层面来说,简直没有扭转,然而底层付出的致力能够说是釜底抽薪了。 上图为驰名的 COLLADA 鸭子模型,在 2012 年转换成 glTF 并加载的成果 1. 加载一个 glTF 模型Model 类将模型的加载、解析职能拆散到一些“资源加载类”。 首先是 GltfLoader 类,这个类负责获取 .glb 或 .gltf 文件,以及连带的任何内部资源,例如二进制文件、贴图图像文件等;glTF 的 JSON 局部经由一系列转换后,会生成一个 ModelComponents 对象,这个对象的构造和 glTF 本人的 JSON 局部很类似,但很多属性都由 CesiumJS 本人的对象来填充。例如,glTF 纹理对象被转换为 CesiumJS 的 Texture 实例,还有几个辅助函数和类用于解析来自下一代 3DTiles 引入的 EXT_mesh_features、EXT_structural_metadata 扩大,以获取更丰盛的信息。 ...

October 25, 2022 · 4 min · jiezi

关于cesium:教程-深度探讨在-Vue3-中引入-CesiumJS-的最佳方式

因为 Vue2 曾经进入保护期,且 Vue2 看待组件内的 data 是无差别应用 Object.defineProperties 递归将其劫持的,对于简单状态的对象会造成重大的 JavaScript 拜访门路过长而导致的 性能问题,这个应该是陈词滥调了。 Vue3 提供了 markRaw 函数,标记一个对象,令 Vue 不再将其视作 响应式 数据,所以本文基于 Vue3 来介绍如何引入 CesiumJS。 心急的敌人能够间接跳过本文的介绍,拉到文末,有示例工程 zip 下载。1. 你应该先晓得的基础知识除了 Vue3 和 Vue2 的响应式设计区别外,我认为还须要补充一点常识。 1.1. CesiumJS 的库形成Cesium 是一个高度集成的重型 JavaScript 库,这是共识。它的源码尽管是 ESModule 格局的,然而并没有间接提供相似 index.js 的进口文件,也不存在子包的概念,只是在 Source 文件夹下简略分了几个大板块文件夹,例如 Source/Renderer 文件夹就是 CesiumJS 中整个渲染器的代码模块。 通常,除了二次批改 CesiumJS 源代码构建本人的分支版本,个别不会在 WebAPP 中间接应用 CesiumJS 的源码。个别应用的是 CesiumJS 的 构建版本,也就是 Build 文件夹下的压缩版或未压缩版库文件。 主库文件有三种格局,ESModule 的是 index.js,IIFE 的是 Cesium.js,CommonJS 的是 index.cjs。除了主库文件外,形成构建版本的 CesiumJS 还有 4 个文件夹下的动态资源: ...

August 26, 2022 · 5 min · jiezi

关于cesium:CesiumJS-更新日志-196-与-197-新构建工具-esbuild-体验及-Model-API-更替完成

CesiumJS 更新日志 1.96 与 1.97 - 新构建工具 esbuild 体验及 Model API 更替实现 截止发文,1.97 还未公布,但曾经在源码仓库实现了 Model API 的替换,文章会跟进。本文着重介绍新的构建指令的用法(配套 esbuild 的应用),见第三节。 首先介绍 1.96 和 1.97 两个大版本的更新内容。 1.96 更新状况1.96 已于 2022 年 8 月初更新;重大更新如下: 改用 esbuild 实现库程序的构建,并更新了一批 npm script(与之前的很不一样);Model.boundingSphere 属性当初返回 ECEF(地心地固)坐标系下的坐标值,也就是世界坐标(EPSG:4978)而不是模型原来的部分坐标;具备 CESIUM_primitive_outline 扩大的 glTF 模型或 Cesium 3DTiles 数据,当初能够通过管制 showOutline 属性来显示外廓线了;未来有可能退出 outlineColor 属性管制色彩;应用模型 API 新架构(1.97将正式代替旧版 Model API,下文不再反复形容)制作的点云类型 3DTiles 当初反对了款式化;降级 earcut 库至 2.2.4 版本,晋升了 10% 到 15% 的性能;修复新 Model API 的若干 bug,包含但不限于 draco 点云示例解体的问题、cmpt 瓦片数据示例缓存不失常的问题、具备透明度的模型示例不更新的问题、逐因素后处理(per-feature post-processing)不失效的问题、具备量化坐标的 i3dm 瓦片数据不能正确加载的问题等;1.96 有两项过期 API 音讯: ...

August 8, 2022 · 3 min · jiezi

关于cesium:Cesium常用坐标转换

罕用坐标转换APIAPI阐明Cesium.Cartographic.fromCartesian(cartesian, ellipsoid, result)笛卡尔转弧度Cesium.Cartographic.fromDegrees(longitude, latitude, height, result)经纬度转弧度(度单位)Cesium.CesiumMath.toDegrees(radians)弧度转度Cesium.CesiumMath.toRadians(degrees)度转弧度Cesium.Cartographic.fromRadians(longitude, latitude, height, result)经纬度转弧度(弧度单位)Cesium.Cartographic.toCartesian(cartographic, ellipsoid, result)弧度转笛卡尔var pick1= scene.globe.pick(viewer.camera.getPickRay(pt1), scene) //其中pt1为一个二维屏幕坐标平面坐标转三维坐标(其实都是笛卡尔坐标)var geoPt1= scene.globe.ellipsoid.cartesianToCartographic(pick1) //其中pick1是一个Cesium.Cartesian3对象笛卡尔三维坐标转地理坐标var point1=[geoPt1.longitude / Math.PI 180,geoPt1.latitude / Math.PI 180]; //其中geoPt1是一个地理坐标地理坐标转经纬度var cartographic = Cesium.Cartographic.fromDegree(point) //point是经纬度值经纬度转地理坐标(弧度)var coord_wgs84 = Cesium.Cartographic.fromDegrees(lng, lat, alt);//单位:度,度,米经纬度转地理坐标var cartesian = Cesium.Cartesian3.fromDegree(point)经纬度转笛卡尔坐标笛卡尔坐标系apiAPI阐明Cesium.Cartesian3.abs(cartesian, result)计算绝对值Cesium.Cartesian3.add(left, right, result)计算两个笛卡尔的重量和Cesium.Cartesian3.angleBetween(left, right)计算角度(弧度制)Cesium.Cartesian3.cross(left, right, result)计算叉积Cesium.Cartesian3.distance(left, right)计算两点间隔Cesium.Cartesian3.distanceSquared(left, right)计算两点平方间隔Cesium.Cartesian3.divideByScalar(cartesian, scalar, result)计算标量除法Cesium.Cartesian3.divideComponents(left, right, result)计算两点除法Cesium.Cartesian3.dot(left, right)计算点乘Cesium.Cartesian3.equals(left, right)比拟两点是否相等Cesium.Cartesian3.fromArray(array, startingIndex, result)从数组中提取3个数构建笛卡尔坐标Cesium.Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result)将将纬度转换为笛卡尔坐标(单位是度°)Cesium.Cartesian3.fromDegreesArray(coordinates, ellipsoid, result)返回给定经度和纬度值数组(以度为单位)的笛卡尔地位数组。Cesium.Cartesian3.fromDegreesArrayHeights(coordinates, ellipsoid, result)返回给定经度,纬度和高度的笛卡尔地位数组Cesium.Cartesian3.fromElements(x, y, z, result)创立一个新的笛卡尔坐标Cesium.Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result)返回笛卡尔坐标以弧度制的经纬度Cesium.Cartesian3.fromRadiansArray(coordinates, ellipsoid, result)返回笛卡尔坐标以弧度制的经纬度数组Cesium.Cartesian3.fromRadiansArrayHeights(coordinates, ellipsoid, result)返回笛卡尔坐标以弧度制的经纬度高度数组Cesium.Cartesian3.fromSpherical(spherical, result)将提供的球面转换为笛卡尔系Cesium.Cartesian3.lerp(start, end, t, result)应用提供的笛卡尔数来计算t处的线性插值或外推。Cesium.Cartesian3.magnitude(cartesian)计算笛卡尔长度Cesium.Cartesian3.magnitudeSquared(cartesian)计算提供的笛卡尔平方量级Cesium.Cartesian3.maximumByComponent(first, second, result)比拟两个笛卡尔并计算蕴含所提供笛卡尔最大成分的笛卡尔。Cesium.Cartesian3.maximumComponent(cartesian)计算所提供笛卡尔坐标系的最大重量的值Cesium.Cartesian3.midpoint(left, right, result)计算右笛卡尔和左笛卡尔之间的中点Cesium.Cartesian3.minimumByComponent(first, second, result)比拟两个笛卡尔并计算蕴含所提供笛卡尔的最小重量的笛卡尔Cesium.Cartesian3.minimumComponent(cartesian)计算所提供笛卡尔坐标系的最小重量的值Cesium.Cartesian3.mostOrthogonalAxis(cartesian, result)返回与提供的笛卡尔坐标最正交的轴Cesium.Cartesian3.multiplyByScalar(cartesian, scalar, result)将提供的笛卡尔重量乘以提供的标量Cesium.Cartesian3.multiplyComponents(left, right, result)计算两个笛卡尔的重量积Cesium.Cartesian3.normalize(cartesian, result)计算所提供笛卡尔的规范化模式Cesium.Cartesian3.pack(value, array, startingIndex)将提供的实例存储到提供的数组中Cesium.Cartesian3.projectVector(a, b, result)将向量a投影到向量b上Cesium.Cartesian3.subtract(left, right, result)计算两个笛卡尔重量差Cesium.Cartesian3.unpack(array, startingIndex, result)从压缩的数组中检索实例Cesium.Cartesian3.unpackArray(array, result)将笛卡尔重量数组解包为笛卡尔数组

July 20, 2022 · 1 min · jiezi

关于cesium:CesiumJS-2022^-源码解读6-三维模型ModelExperimental新架构

三维模型架构(即 Scene/ModelExperimental 目录下的模块)有别于旧版模型 API(即 Scene/Model.js 模块为主的一系列解决 glTF 以及解决 3DTiles 点云文件的源码),它从新设计了 CesiumJS 中的场景模型加载、解析、渲染、调度架构,更正当,更弱小。 这套新架构专门为 下一代 3DTiles(1.1版本,以后临时作为 1.0 版本的扩大)设计,接入了更弱小的 glTF 2.0 生态,还向外裸露了 CustomShader API。 ModelExperimental 的尾缀 Experimental 单词即“实验性的”,期待这套架构欠缺,就会去掉这个尾缀词(截至发文,CesiumJS 版本为 1.95)。 接下来,我想先从这套架构的缓存机制说起。 1. ModelExperimental 的缓存机制1.1. 缓存池 ResourceCache缓存机制由两个主治理类 ResourceCache 和 ResourceCacheKey 负责,缓存的可不是 Resource 类实例,而是由 ResourceLoader 这个基类派生进去的 N 多个子类: ResourceCache 类被设计成一个相似于“动态类”的存在,很多办法都是在这个类身上应用的,而不是 new 一个 ResourceCache 实例,用实例去调用。例如: ResourceCache.get("somecachekey...") // 应用键名获取缓存的资源ResourceCache.loadGltfJson({ /* . */}) // 依据配置对象加载 glTF 的 json下面提到,ResourceCache 缓存的是各种 ResourceLoader,实际上为了统计这些 loader 被应用的次数,Cesium 团队还做了一个简略的装璜器模式封装,即应用 CacheEntry 这个在 ResourceCache.js 模块内的公有类: ...

June 30, 2022 · 9 min · jiezi

关于cesium:基于Mars3DCesium第三方库的动态模型间连线

在应用基于Cesium的Mars3D第三方库做开发的时候,碰到了这么一个需要:“实现两个模型之间的连线,这个直线能够随着模型的挪动而挪动”。 Mars3D中提供了一个标绘性能,简略来说就是能够通过拖动鼠标扭转模型在图层上的地位。所以提出的需要就简化成了————“鼠标拖动模型,模型间的连线随着模型挪动而挪动”。 这里模型的挪动形式对于后续的计划解决有很大的影响。首先我来讲讲第一种计划失败的可能起因。 计划一(失败)model的position应用PositionProperty, polyline的position应用PositionPropertyArray,array数组外面是ReferenceProperty, 这里是为了让polyline两端的地位依赖于模型的地位。这种计划是能够胜利显示出连线的,然而问题出在标绘上。调用提供的标绘函数的时候,会呈现如图的谬误在ReferenceProperty的api文档中提到了只有援用的属性是PositionProperty是这个函数才无效。然而咱们在最后设定模型position的时候的确是应用的PositionProperty,这里我猜测应该是标绘函数应用了一个CallbackProperty,回调的Object不再是PositionProperty类型了,因而会出错。Mars3D的api并没有开源,具体起因也无从得悉了。 计划二(胜利)既然咱们想用Mars3D的api实现咱们的需要,就须要另辟蹊径。第二种计划应用了czml数据格式,czml数据配置项中的polyline/position属性有一个references选项, 应用它也能够实现地位依赖。 "polyline":{ "positions":{ "references":[ "model1#position", "model2#position" ] } }新的问题便是:怎么引入这个czml数据?Mars3D中提供了很多图层,这些图层都具备不同的性能。咱们上文中提到的标绘性能,是基于graphicLayer的,然而graphicLayer并不反对导入czml,Mars3D独自提供了czmlLayer能够导入czml配置文件。因而采纳“双图层同步”的解决方案:graphicLayer上的标绘扭转模型地位后,应用监听事件获取扭转后的模型坐标,同步更新czml配置文件的相应模型的position属性内容,并更新czmlLayer图层。graphicLayer显示模型,czmlLayer中的配置项中仅仅记录模型的地位,不显示模型,只显示polyline。简略来说,graphicLayer上的模型和czmlLayer的模型实际上是两个独自的实体,只是通过监听事件让这它们的地位时刻保持一致。 //模型绑定监听事件 this.graphicLayer.getGraphicById("Firecar").on(mars3d.EventType.updatePosition,function (event){ //console.log("地位产生了变动!",event) console.log(event.position.getValue(Cesium.JulianDate.fromDate(new Date('2022-06-16 08:00:00')))) that.czml.forEach(function(value,index,array){ if(value.id ==='Firecar') value.position = { "cartographicDegrees": (mars3d.LngLatPoint.fromCartesian(event.position.getValue(Cesium.JulianDate.fromDate(new Date('2022-06-16 08:00:00'))))).toArray(false) } }); //更新czml图层 that.czmlLayer.load() console.log(that.czmlLayer) })须要留神的点:监听事件返回的是一个event,event外面有监听的position属性,这个属性是一个callbackProperty,应用getValue办法传入轻易一个工夫值得到变动后的坐标,留神失去的这个坐标是cartesian3,更新czml时候要将cartesian3换成array,这样直线才会失常显示。 这里的代码只是示意,目标还是为了分享解决思路。

June 19, 2022 · 1 min · jiezi

关于cesium:超图iClient-webgl引擎场景定位问题

最近公司用到超图iclient引擎的能力,须要实现点击按钮定位到超图某个歪斜摄影场景的性能。超图官网提供的API只有创立实例时传递autoSetView主动定位到场景,代码如下: // 萨尔茨堡服务地址let url = "http://www.supermapol.com/realspace/services/3D-srsb/rest/realspace";// 加载场景const cbdPromise = scene.open(url, undefined, { autoSetView: true // 自定定位});然而,如果想要加载模型是不定位,点击按钮后再定位autoSetView就无奈满足了。 通过一番摸索后,通过如下代码实现的性能: // 加载场景const cbdPromise = scene.open(url, undefined, { autoSetView: false // 敞开主动定位});// 申请场景列表axios.get(`${url}/scenes.json`) .then(([{ path }]) => { // 申请场景列表中第一个场景的相机信息,并定位。如存在多个场景须要加载多个场景后,计算多个场景的边界再进行定位 axios.get(`${path}.json`) .then(({ camera: { altitude, heading, latitude, longitude, tilt } }) => { scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, altitude), orientation: { heading: Cesium.Math.toRadians(heading), pitch: Cesium.Math.toRadians(tilt - 90), roll: 0.0 } }); }); });

June 6, 2022 · 1 min · jiezi

关于cesium:CesiumJS-2022^-原理5-着色器相关的封装设计

本篇波及到的所有接口在公开文档中均无,须要下载 GitHub 上的源码,本人创立公有类的文档。 npm run generateDocumentation -- --privateyarn generateDocumentation -- --privatepnpm generateDocumentation -- --private本篇当然不会波及着色器算法解说。 1. 对 WebGL 接口的封装任何一个有谋求的 WebGL 3D 库都会封装 WebGL 原生接口。CesiumJS 从外部封测到当初,曾经有十年了,WebGL 自 2011 年公布以来也有 11 年了,这期间小修小补不可避免。 更何况 CesiumJS 是一个 JavaScript 的天文 3D 框架,它在源代码设计上具备两大特色: 面向对象模块化对于模块化策略,CesiumJS 在 1.63 版本曾经从 require.js 切换到原生 es-module 格局了。而 WebGL 是一种应用全局状态的指令式格调接口,改为面向对象格调就必须做封装。ThreeJS 是通用 Web3D 库中做 WebGL 封装的代表作品。 封装有另外的益处,就是底层 WebGL 接口在这十多年中的变动,能够在封装后屏蔽掉这些变动,下层利用调用封装后的 API 形式根本不变。 1.1. 缓冲对象封装CesiumJS 封装了 WebGLBuffer 以及 WebGL 2.0 才正式反对(1.0 中用扩大)的 VAO,别离封装成了 Buffer 类和 VertexArray 类。 ...

May 15, 2022 · 8 min · jiezi

关于cesium:CesiumJS-2022^-原理4-最复杂的地球皮肤-影像与地形的渲染与下载过程

API 回顾在创立 Viewer 时能够间接指定 影像供应器(ImageryProvider),官网提供了一个非常简单的例子,即离屏例子(搜 offline): new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.TileMapServiceImageryProvider({ url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"), })})这个例子的影像供应器是 TMS 瓦片服务,也就是预制瓦片地图,资源位于 Source/Assets/Textures/NaturalEarthII 文件夹下。 若没有指定 地形供应器(TerrainProvider),Cesium 也有默认策略: // Globe.js 构造函数内const terrainProvider = new EllipsoidTerrainProvider({ ellipsoid: ellipsoid,})这就是说,应用 EllipsoidTerrainProvider 来作为默认地形,也就是把椭球面当作地形(因为没有)。 小提示:TileMapServiceImageryProvider 其实是 UrlTemplateImageryProvider 的一个子类,在文章最初一节申请瓦片时会再次提及。本篇要解决的两大疑难: 椭球体是如何形成的瓦片是如何从创立到申请,最终到渲染的这篇比拟长,不计代码也有 8000 多字,而且波及的数据类比拟多,然而我感觉能实现上述两个过程的大抵解说,就能沿着思路细化钻研上来了。 1. 对象层级关系其下层上层的次要类从属关系(从 Scene 开始算起)大抵是: Scene┖ Globe ┠ Ellipsoid ┖ QuatreePrimitive ┠ GlobeSurfaceTileProvider ┖ QuadtreeTile ┖ GlobeSurfaceTile ┠ TileImagery[] ┃ ┖ Imagery ┖ TerrainData我简化了 ImageryLayer、ImageryProvider、ImageryLayerCollection、TerrainProvider 与下面这些类的关系,也就没让他们呈现在图中。 1.1. Scene 中非凡的物体 - GlobeScene 下辖的次要三维容器是 PrimitiveCollection,能持续往里套 PrimitiveCollection,也能够独自放类 Primitive。 ...

May 9, 2022 · 7 min · jiezi

关于cesium:Cesium-DrawCommand-1-不谈地球-画个三角形

0. 前言Primitive API 是公开的 API 的最底层了,它面向的场景是高性能、可自定义材质着色器(Appearance API + FabricMaterial Specification)、动态三维物体。 尽管如此,Primitive API 依然封装了大量几何体类、材质类、WebWorker,而且目前凋谢自定义着色器 API 的只有三维模型类的新架构,还没下放到 Primitive API。 如果 API 包袱不想那么重,又心愿能够应用本人的模型格局(必须是三角面),那么公有的 DrawCommand + VertexArray 接口就十分适合了,它的格调曾经是最靠近 CesiumJS WebGL 底层的一类 API 了。 DrawCommand,是 Cesium 封装 WebGL 的一个优良设计,它把绘图数据(VertexArray)和绘图行为(ShaderProgram)作为一个对象,待机会适合,也就是 Scene 执行 executeCommand 函数时,帧状态对象上所有的指令对象就会应用 WebGL 函数执行,要什么就 bind 什么,做到了在绘图时的用法统一,下层利用接口只需生成指令对象。 0.1. 源码中的 DrawCommand譬如在 Primitive.js 模块中的 createCommands 函数,它就是负责把 Primitive 对象的参数化数据或 WebWorker 计算来的数据合并生成 DrawCommand 的中央: function createCommands(/* 参数省略 */) { // ... const length = colorCommands.length; let vaIndex = 0; for (let i = 0; i < length; ++i) { let colorCommand; // ... colorCommand = colorCommands[i]; if (!defined(colorCommand)) { colorCommand = colorCommands[i] = new DrawCommand({ owner: primitive, // 入参,即 Primitive 对象 primitiveType: primitive._primitiveType, }); } colorCommand.vertexArray = primitive._va[vaIndex]; // VertexArray colorCommand.renderState = primitive._frontFaceRS; // 渲染状态 colorCommand.shaderProgram = primitive._sp; // ShaderProgram colorCommand.uniformMap = uniforms; // 对立值 colorCommand.pass = pass; // 该指令的通道程序 } // ...}1. 创立1.1. 形成因素 - VertexArrayCesium 把 WebGL 的顶点缓冲和索引缓冲包装成了 Buffer,而后为了不便,将这些顶点相干的缓冲绑定在了一个对象里,叫做 VertexArray,外部会启用 WebGL 的 VAO 性能。 ...

April 28, 2022 · 5 min · jiezi

关于cesium:CesiumJS-2022^-原理3-渲染原理之从-Entity-看-DataSource-架构

API 用法回顾只需传入参数对象,就能够简略地创立三维几何体或者三维模型。 const modelEntity = viewer.entites.add({ id: 'some-entitiy', name: 'some-name', position: Cartesian3.fromDegrees(112.5, 22.3, 0), model: { uri: 'path/to/model.glb' }})Entity API 通常会被拿来与 Primitive API 比拟,无外乎: 前者应用 Property API 使得动态效果简单化,后者须要本人编写着色器;个体数量较多时,前者的性能不如后者;后者反对较底层的用法,能够本人管制材质着色器、几何数据并批优化;...本篇感兴趣的是 Entity API 是如何从参数化对象到 WebGL 渲染的。 首先,上论断:Entity 最终也会变成 Primitive。 从下面简略的示例代码能够看出,应用 Entity API 的入口是 Viewer,它不像 Primitive API 是从 Scene 拜访的。 这正是对于 Entity API 源代码和设计架构的第一个常识,Entity API 必须依赖 Viewer 容器。 前提是只用公开出来的 API1. 为什么要从 Viewer 拜访 Entity APIViewer 其实是 CesiumJS 长期保护的一个成绩,它在大多数时候表演的是 Web3D GIS 地球的总入口对象。明天的配角是它裸露进去的 Entity API,不过在介绍它之前,还要再提一提 Scene 裸露进去的 Primitive API ...

April 17, 2022 · 7 min · jiezi

关于cesium:CesiumJS-2022^-原理2-渲染架构之三维物体-创建并执行指令

回顾书接上文,Scene.js 模块内的 render 函数会将控制权交给 WebGL,执行 CesiumJS 本人封装的指令对象,画出每一帧来。 模块内的 render 函数首先会更新一批状态信息,譬如帧状态、雾效、Uniform 值、通道状态、三维场景中的环境信息等,而后就开始更新并执行指令,调用的是 Scene 原型链上的 updateAndExecuteCommands 办法。 整个过程大抵的调用链是这样的(function 关键字简写为 fn): [Module Scene.js]- fn render() - Scene.prototype.updateAndExecuteCommands() - fn executeCommandsInViewport() - fn updateAndRenderPrimitives() [Module Primitive.js] - fn createCommands() - fn updateAndQueueCommands() - fn executeCommands() - fn executeCommand()本篇解说的是从 Scene 原型链上的 updateAndExcuteCommands() 办法开始,期间 Scene 中的 Primitives 是如何创立指令,又最终如何被 WebGL 执行的。 这个过程波及十分多细节代码,然而为了疾速聚焦整个过程,本篇先介绍两个 CesiumJS 封装的概念:指令和通道。 准备常识:指令WebGL 是一种依赖于“全局状态”的绘图 API,面向对象特色比拟弱,为了批改全局状态上的顶点数据、着色器程序、帧缓冲、纹理等“资源”,必须通过 gl.XXX 函数调用触发全局状态的扭转。 而图形编程根底提出的渲染管线、通道等概念偏差于面向对象,显然 WebGL 这种偏过程的格调须要被 JavaScript 运行时引擎封装。 CesiumJS 将 WebGL 的绘制过程,也就是行为,封装成了“指令”,不同的指令对象有不同的用处。指令对象保留的行为,具体就是指由 Primitive 对象(不肯定全是 Primitive)生成的 WebGL 所需的数据资源(缓冲、纹理、惟一值等),以及着色器对象。数据资源和着色器对象依然是 CesiumJS 封装的对象,而不是 WebGL 原生的对象,这是为了更好地与 CesiumJS 各种对象联合去绘图。 ...

April 11, 2022 · 3 min · jiezi

关于cesium:CesiumJS-2022^-原理1-使用-requestAnimationFrame-循环触发帧动画

0. 前置约定对类的应用,不增加 Cesium 命名空间前缀,例如对于 Viewer,不会写 Cesium.Viewer,默认应用 ESM 格局解构导入类;JavaScript 代码应用最简格局(源码除外),不加分号,不必双引号,少正文,双空格缩进本系列阐明佛系连载,想到什么写什么。 2022 年,写原理类的文显得十分“蠢”,大家都想吃快餐,看成果。法克鸡丝老哥的系列博客思路跳跃很快,单步阐明之间的信息量很大,须要消化很长时间能力啃完一篇文章,遂决定另开一个格调,提纲挈领地把次要要害逻辑大白话说说 —— 可不是真的“大白话”,还是要有一些功底的。 我写这个,只是为了从 CesiumJS 的渲染架构中吸取一些养分,心愿对本人的程序设计能力有进步,心愿能从其它绘图 API 的角度看看能不能优化和实现。 1. 开始很多人写 CesiumJS 程序是从 Viewer 开始的 new Viewer('container') // div id你若只须要一个最洁净的场景(此场景非 Scene 类),不须要工夫条、工夫控制器、右上角一堆的按钮,只须要 new CesiumWidget('container') // div idCesiumJS 内置了大量的默认值,以至于简略到你能够只传递 DOM 的 id 或自身即可创立场景。 1.1. CesiumWidget 类是管制场景对象触发渲染的调度器Scene 类是一个三维空间对象的容器,它在原型链上有一个 render 办法,寥寥百行,管制了三维场景中若干物体的更新、渲染。 Scene.prototype.render 办法调用一次,只更新并渲染一帧。 家喻户晓,WebGL 个别会和 requestAnimationFrame, rAF 这个 API 循环调用渲染函数。而让 canvas 中场景能间断多帧周而复始运行的调度者,是 CesiumWidget 类。 CesiumWidget 类有一个应用 Object.defineProperties() 办法定义的 setter: useDefaultRenderLoop: { get: function () { return this._useDefaultRenderLoop; }, set: function (value) { if (this._useDefaultRenderLoop !== value) { this._useDefaultRenderLoop = value; if (value && !this._renderLoopRunning) { startRenderLoop(this); } } },}在实例化 CesiumWidget 时,它会应用传入的值,若没有,则是 true: ...

April 6, 2022 · 2 min · jiezi

关于cesium:Cesium-191-更新日志-MSAA-与原生-Promise-来了

不兼容式更新在下一个版本,也就是 Cesium 1.92,第三方库 when.js 将被原生 Promise API 代替。Cesium.when 将被废除,且于下个版本移除。对于如何降级,请参考下方集体点评,我转载了官网领导文档。修复了当 Scene 没有渲染时(例如 css 款式设为 none)相机对象的获取射线办法(camera.getPickRay())引发的异样,这个函数会返回 undefined 了。新增为 WebGL 2.0 增加 MSAA(多重采样抗锯齿)反对。你能够在创立 Viewer 时传递 msaaSamples 选项,也能够用 Scene.msaaSamples 属性管制。当初,glTF 模型默认应用 ModelExperimental 架构解决。在 ModelExpertimental 架构中反对切换反面裁剪。向 Viewer 和 Scene 类的结构参数中增加 depthPlaneEllipsoidOffset,以解决椭球体立体之下的奇怪渲染问题在 ModelExperimental 架构中反对了 debugColorTiles在 ModelExperimental 架构中反对了暗影在所有的矩阵类中增加了 packArray 和 unpackArray 办法为矩阵类增加一些仿射变换帮忙函数 Matrix2:setScale、setUniformScale、setRotation、getRotation、multiplyByUniformScaleMatrix3:setScale、setUniformScale、setRotation、multiplyByUniformScaleMatrix4:setUniformScale、setRotation、getRotation、fromRotation为 AxisAlignedBoundBox 类增加 fromCorners 办法为 BoundingSphere 类增加 fromTransformation 办法为 OrientedBoundingBox 类增加 fromTransformation、computeCOrners、computeTransformation 办法为 Rectangle 类增加 subsection 办法glTF 的版权信息会标注至版权区域为 3D Tiles 减少一个选项,它能够决定数据集的版权信息是否显示在屏幕上批改了版权排序规定为呈现的频率问题修复修复了应用 ModelExperimental 架构的模型在更新其模型矩阵时不会更新范畴球的谬误修复了在 Safari 浏览器中 FeatureID 纹理的伪影修复了应用 ModelExpertimental 架构的不通明模型应用半透明着色器,然而未正确渲染的谬误集体点评① MSAAMSAA 就不用说了,举荐条件不错的机器都开,配合 FXAA 晋升显示成果。 ...

March 2, 2022 · 1 min · jiezi

关于cesium:为何在打包工具中导入-Cesium-的-css-失败了

1 问题起因我应用 vite2 + vanillajs 模板创立 CesiumJS 我的项目,其中,main.js 是这样的: import { Viewer } from 'cesium'import './style.css'import 'cesium/Source/Widgets/widgets.css'let viewerconst main = () => { const dom = document.getElementById('app') viewer = new Viewer(dom)}document.addEventListener('DOMContentLoaded', () => { main()})看起来逻辑完满,思路清晰,没什么特地的疑难点。于是我就吭哧吭哧地运行起 npm script: pnpm dev可是,Vite 在控制台给我报了个错: [vite] Internal server error: Missing "./Source/Widgets/widgets.css" export in "cesium" package这个问题貌似在各前端框架的模板中是不会呈现的,我不确定。也有人在 Webpack 中遇到了这个相似的状况,究其原因,我认为还是 cesium 包的导出有些不齐备,见上面第二节的剖析。简略点说,就是 Vite 的内置预构建工具 esbuild 在搜寻依赖树时,没有找到 "cesium" 包导出的一个门路为 "./Source/Widgets/widgets.css" 文件。 2 寻找解决方案可是,当我关上 node_modules/cesium/Source/Widgets/ 目录,widgets.css 文件确实就在那里放着。 于是我关上了谷歌,果不其然找到了相似的 issue:github.com/CesiumGS/cesium issue#9212,我在 2021 年 8 月也跟帖回复了我的状况。 ...

February 28, 2022 · 2 min · jiezi

关于cesium:下一代-3DTilesNext详解-0-文章目录

篇1 总体简介篇2 瓦片数据内容扩大之 3DTILES_content_gltf篇3 瓦片数据内容扩大之 3DTILES_multiple_content篇4 瓦片组织模式扩大之 3DTILES_implicit_tiling篇5 瓦片组织模式扩大之 3DTILES_bounding_volume_S2篇6 瓦片属性数据组织扩大之 3DTILES_metadata 未完待续

January 21, 2022 · 1 min · jiezi

关于cesium:下一代-3DTilesNext详解-6-瓦片属性数据组织扩展之-3DTILESmetadata

依赖于3D Tiles 1.0 可选与必须如果用到了属性元数据,那么这项扩大必须同时呈现在 extensionsUsed 和 extensionsRequired 数组中,即“必须的”。 1. 概述此扩大定义了一种在 3D Tiles 中存储结构化的元数据的机制,这些元数据个别又称作 属性数据,起源宽泛,可用于数据查看、剖析、款式化 3D Tiles 或者其余用处。 在本文中,我暂且称之为属性元数据。这些属性数据要依据模板来记录,这种模板被称作“Schema(模式)”,使得属性数据有章可循。而且,不同层级的对象(最大的对象是 Tileset,顺次向下为 Tile 等)有不同的关联形式。 下列阐明不同层级的对象的元数据(属性)的细节: 对于 Tileset 级别,属性元数据记录的是整个数据集级别的信息,比方数据公布年份等对于 Tile 级别,属性元数据能够记录更细粒度的信息,例如瓦片数据内容的最大高度等对于 Tile Content Groups 级别,能够将分组后的瓦片数据内容的属性元数据也分组来存储对于瓦片数据内容外面的三维因素级别,也能够有属性元数据,参考 3.5 更深层次的因素级属性元数据 本扩大中的概念均为 三维元数据标准(3D Metadata Specification) 的落实。 下图展现了 3D Tiles 中各个级别的对象(tileset、tiles、content、group)之间的关系及属性元数据的实例: 属性元数据有什么用间接查看:在界面上鼠标滑过或点击瓦片时,展现属性元数据分组:瓦片的数据内容能够分组,每个组能够有本人的属性元数据,这样就能够依据每个组本人的属性元数据来管制显示暗藏等组内瓦片全副统一的操作反对简单格局的数据:此扩大反对 Schema 嵌入在 JSON 内,也反对内部援用,这样各个领域的专家就能够把行业数据编入其中渲染优化:属性元数据可能会蕴含一些性能优化相干的参数,这样能够在遍历等有须要的时候优化相干算法2. 属性元数据2.1. 概述Property 形容某个实体(实体指 Tileset、Tile 或者 TileGroup)的信息。 Schema 为 Class 定义数据类型等元数据信息。 每个实体,都是 Class 的具体实例,有着 Class 内记录的数据值。 此外,Statistics 可把特定 Class 内的统计值抽取进去独自存储;Semantic 则用于定义特定 Property 的用法和含意。 ...

January 21, 2022 · 6 min · jiezi

关于cesium:下一代-3DTilesNext详解-5-瓦片组织形式扩展之-3DTILESboundingvolumeS2

依赖于3D Tiles 1.0 可选与必须必须同时呈现在 extensionsUsed 和 extensionsRequired 数组中,即“必须的”。 1. 概述S2 是一个用于定义单位球体外表的网格框架的程序库,一个网格单元(又叫单元格,Cell)将会横竖各取一半来分成 4 个子单元格,单元格的四个边界线均为测地线(即沿着高空的“直线”)。 S2 所定义的这套地表的网格层次结构,有 6 个根单元格。每个根单元格是由单位立方体投影到球面上取得的。 译者注,单位立方体投影到球面这个形容其实不精确,严格来说是单位立方体各个面与球心连贯而成的四棱锥,与球面相交失去的那 6 个测地四边形。见本文上面的图。通常,传统的 GIS 会把地球椭球体投影到某个立体或可展成立体的曲面(圆锥、圆柱)上。例如,墨卡托投影就是投影到圆柱体上。墨卡托有一个家喻户晓的问题,那就是离极点越近,形变越大。 S2 这种投射形式就改善了墨卡托的问题,并还有其它的益处,它把地外表宰割成没有奇怪端点、形变较小、瓦片相对来说简直相等的瓦片。 基于上述特色,应用 S2 定义的这套瓦片层次结构的 3D Tiles Next 扩大就特地适合逾越寰球范畴的瓦片数据集。 2. 层级S2 层级构造中,每个根网格测地四边形(称作“单元格”)能细分到 30 级。下图展现第 "1" 个单元格及其 4 个子单元格的图例: 第 0 级(根 Cell)第 1 级(根 Cell 的子级 Cell)第一行是地球立方体的第 "1" 个 Cell 及其子 Cell,第二行则是椭球面上的第 "1" 个 Cell 及其 4 个子 Cell,其中子 Cell 上的编号“0c”、“14”等暂且不论,编号会在下文“单元格ID”大节中具体解释。 S2 应用改版希尔伯特曲线来编码一维程序的网格编号,给每一级别任意单元格提供了64位的ID,最高层级的单元格能够准确到厘米级空间范畴。 察看 S2 希尔伯特曲线如下: 在地球立方体外表上在地球椭球面上3. 单元格ID单元格ID 应用 64 位宽度的二进制比特位来编码,从左到右的比特位的规定: ...

January 21, 2022 · 3 min · jiezi

关于cesium:下一代-3DTilesNext详解-4-瓦片组织形式扩展之-3DTILESimplicittiling

依赖于3D Tiles 1.0 可选与必须如果瓦片在空间索引规定上用到了隐式宰割,那么这项扩大必须同时呈现在 extensionsUsed 和 extensionsRequired 数组中,即“必须的”。 1. 概述Implicit tiling,译作 隐式瓦片宰割,是一种 3D Tileset 的新的空间宰割形式,它容许运行时疾速、随机拜访瓦片,而且应用了新的遍历算法。 隐式瓦片宰割的空间数据结构一律应用四叉树或者八叉树。这两种常见的构造让瓦片的组织更紧凑,也能让 tileset.json 文件更小。 扩大项 3DTILES_implicit_tiling 能够作用于任意一个 Tile,它定义的信息次要是瓦片的空间宰割状况以及对应的文件资源信息。 有一些数据,并不是所有瓦片都能满填充的,这种叫 稠密数据集,须要一个叫 availability(可用性) 数据来确定哪些瓦片存在,哪些不存在。这个可用性数据被存储在固定格局的、紧凑的二进制文件中,后缀名是 .subtree。 隐式瓦片宰割容许通过瓦片的索引坐标间接拜访瓦片。当树结构应用的是 quadtrees(四叉树)时,瓦片坐标有三个:level、x、y,而 octrees(八叉树)则是 level、x、y、z,有了瓦片的索引坐标,就能够省去遍历整个瓦片数据集的过程。 对于上述呈现的名词,解释会放到文末。2. Tile 对象中的扩大项写法本扩大项作用于 tileset.json 中任意一个 Tile 对象。被作用的瓦片被称为“隐式宰割根瓦片”,此瓦片必须疏忽 children 属性。 上面是一个例子: { "asset": { "version": "1.0" }, "geometricError": 10000, "extensionsUsed": [ "3DTILES_implicit_tiling" ], "extensionsRequired": [ "3DTILES_implicit_tiling" ], "root": { "boundingVolume": { "region": [-1.318, 0.697, -1.319, 0.698, 0, 20] }, "refine": "REPLACE", "geometricError": 5000, "content": { "uri": "content/{level}/{x}/{y}.b3dm" }, "extensions": { "3DTILES_implicit_tiling": { "subdivisionScheme": "QUADTREE", "maximumLevel": 20, "subtrees": { "uri": "subtrees/{level}/{x}/{y}.subtree" }, "subtreeLevels": 7 } } }}实践上来说,有隐式宰割扩大的瓦片对象不须要,也没必要存在 boundingVolume(空间范畴长方体)属性,是因为隐式瓦片的宰割规定曾经能够通过瓦片索引坐标计算出这个属性。这里的 root 瓦片之所以存在这个属性是因为 3DTILES_metadata 扩大某些元数据定义须要用到这个属性,例如 CONTENT_BOUNDING_BOX 之类的。 ...

January 21, 2022 · 5 min · jiezi

关于cesium:下一代-3DTilesNext详解-3-瓦片数据内容扩展之-3DTILESmultiplecontent

依赖于3D Tiles 1.0; 本阐明文档还用到了隐式瓦片宰割扩大和元数据扩大,详见 3DTILES_implicit_tiling、3DTILES_metadata 可选与必须如果在瓦片中援用了多个数据文件作为内容,那么这项扩大必须同时呈现在 extensionsUsed 和 extensionsRequired 数组中,即“必须的”。 1. 概述 这项扩大对单个瓦片提供了援用多个数据文件的反对。这多个数据文件,能够是 b3dm、pnts 或者 1.0 中瓦片格局中的任意类型。 上图示意瓦片与内容(数据文件)的关系。 多数据文件(即多内容)让 Tileset 的构造更加灵便。例如,某个瓦片能够援用 b3dm 和 pnts 两种瓦片,都示意同一个建筑物的外表,而运行时则能够选择性地只加载点云的数据。 当此扩大与 3DTILES_metadata 扩大一起应用时,能够把内容(数据文件)打组,每个组能够共享同一份本人的元数据,如下图所示: 上图有三组,红色组散布在右边两个瓦片,代表小车;绿色散布在下面和左下三个瓦片中,代表树木;灰色以此类推。 分组的益处见上图:过滤不想显示的内容,缩小带宽应用。 多内容扩大能够与 3DTILES_implicit_tiling 一起应用,是兼容的。见下文。 2. 概念3DTILES_multiple_contents 扩大作用于 Tile 对象。模式定义见文末。 举例: { "root": { "refine": "ADD", "geometricError": 0.0, "boundingVolume": { "region": [-1.707, 0.543, -1.706, 0.544, 203.895, 253.113] }, "extensions": { "3DTILES_multiple_contents": { "content": [ { "uri": "buildings.b3dm" }, { "uri": "trees.i3dm" } ] } } }}在 root 瓦片的 extensions 属性内,记录了一个 3DTILES_multiple_content 对象,这个对象就记录了两个 content(作为数组)。能够看到这里的多个数据文件组合了 b3dm 和 i3dm,象征这块瓦片的区域内,有修建模型,也有树木模型。 ...

January 21, 2022 · 4 min · jiezi

关于cesium:下一代-3DTilesNext详解-2-瓦片数据内容扩展之-3DTILEScontentgltf

依赖于3D Tiles 1.0 可选与必须如果用到了 glTF 作为瓦片内容文件,那么它必须同时呈现在 extensionsUsed 和 extensionsRequired 数组中,即“必须的”。 1. 简介 上图中有一个瓦片援用了 house.glb,而这个 house.glb 的模型就是一个房子,能够间接被 3D Tiles 的瓦片援用。此处 "content": "house.glb" 是简略写法。 这个扩大容许 3D Tiles 在瓦片文件上间接应用 glTF 2.0 模型文件。同时反对 JSON 格局的 gltf 文件和二进制的 glb 文件。 应用这个扩大能够简化数据的生产,次要就是利用好 glTF 的工具链。大多数时候,1.0 的瓦片数据能够轻易地转为 glTF 格局。 参考 迁徙指南。 2. 示例 JSON具体的 JSON 模式定义在文末。 运行时引擎(通常是 CesiumJS)必须在加载瓦片内容之前,确定兼容性问题。 比方,某些 glTF 模型文件用到了一些 glTF 扩大,那么这些额定的 glTF 扩大就必须写在 Tileset 的顶级属性 extensions 中的 3DTILES_content_gltf 对象中。 举例: { "asset": { "version": "1.0" }, "extensionsUsed": ["3DTILES_content_gltf"], "extensionsRequired": ["3DTILES_content_gltf"], "extensions": { "3DTILES_content_gltf": { "extensionsUsed": ["EXT_mesh_gpu_instancing"], "extensionsRequired": ["EXT_mesh_gpu_instancing"] } }, "geometricError": 240, "root": { "boundingVolume": { "region": [ -1.3197209591796106, 0.6988424218, -1.3196390408203893, 0.6989055782, 0, 88 ] }, "geometricError": 0, "refine": "ADD", "content": { "uri": "trees.gltf" } }}能够看到,这份入口文件的 extensions 属性,下有一个 3DTILES_content_gltf 对象,其下又有两个与 Tileset 相似的 extensionsUsed 和 extensionsRequired 数组。 ...

January 21, 2022 · 2 min · jiezi

关于cesium:下一代-3DTilesNext详解-1-总体介绍

1. 简介3D Tiles Next 是一组针对下一代 3D Tiles 的新性能(或者说 3D Tiles 扩大)。 这些新性能目前以 3D Tiles 1.0 的扩大草案出现,未来可能会合并到 3D Tiles 2.0 中。 2. 对于瓦片数据内容的扩大(Tile Content)2.1. 概述在 Next 中,glTF 2.0 数据将能够间接作为瓦片的内容,不再应用 1.0 的 b3dm、i3dm、pnts 和 cmpt,提供了与 glTF 生态的互通性。瓦片能够援用单个内容,也能够援用多个内容。 瓦片的内容也能够汇合至相似于 2D 地图图层一样的容器组中。 尽管 Next 应用 glTF 作为瓦片文件,不再应用原来的四种瓦片文件格式,然而并不意味着运行时不再应用,这是数据标准版本的区别,而不是运行时立马就要放弃旧标准。 2.2. 扩大 3DTILES_content_gltf3DTILES_content_gltf 这项扩大,容许在 Tile.content 属性上间接援用一个 glTF 模型文件(.gltf 或 .glb)。 2.3. 扩大 3DTILES_multiple_content3DTILES_multiple_content 这项扩大,容许一个瓦片援用多个内容(瓦片文件)。瓦片实际上就是一块空间范畴体,组织起多个瓦片文件是很失常的。 组织模式也多种多样,能够像地图图层一样,也能够轻易分组。 通常会与 [3DTILES_metadata]() 扩大所组织的元数据一起用。 3. 隐式瓦片(Implicit Tiling)3.1. 概述隐式瓦片宰割,意思就是将瓦片的空间范畴和空间索引形式“隐去”,即不显式地记录在瓦片对象中,而这种隐含的空间宰割办法和索引形式,则是默认数据生产者和运行时晓得的。 其无效地缩小了 tileset.json 这个文件的体积,并进步了空间索引的效率,寻找、遍历瓦片的速度更快,射线计算、随机拜访、空间查问也更快了。 除了上述长处,还加强了与 2DGIS 中一些天文数据格式/数据库的互相集成,例如 CDB、TMS、WMTS、S2. ...

January 21, 2022 · 2 min · jiezi

关于cesium:数字孪生之路

理解glTFhttps://cloud.tencent.com/dev...

January 6, 2022 · 1 min · jiezi

关于cesium:记录入门cesiumcesium全球动态贴图使用场景气象海冰分布时序

hint: "@supermap/vue-iclient3d-webgl": "^1.0.9"计划一: imageList = [ {image:require("../../static/Image_15.png")}, {image:require("../../static/Image_16.png")}, {image:require("../../static/Image_17.png")}, {image:require("../../static/Image_18.png")}, {image:require("../../static/Image_19.png")}, {image:require("../../static/Image_20.png")}, {image:require("../../static/Image_21.png")}, {image:require("../../static/Image_22.png")}, {image:require("../../static/Image_23.png")}, {image:require("../../static/Image_24.png")}, {image:require("../../static/Image_25.png")}, {image:require("../../static/Image_26.png")}, {image:require("../../static/Image_27.png")}, {image:require("../../static/Image_28.png")}, {image:require("../../static/Image_29.png")}, {image:require("../../static/Image_30.png")} ]setInterval(() =>{ let newPic = that.imageList.shift() viewer.imageryLayers.remove() let c = viewer.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url : newPic.image })); that.imageList.push(newPic) setTimeout(() =>{ viewer.imageryLayers.remove(c) },430) },230)论断:十分吃性能,切图太快了就不行。计划二:采纳了CallbackProperty类回调函数提早计算,它能够实时自我调用。要求:肯定是寰球贴图。 this.entities = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( -180.0, -90.0, 180.0, 90.0 ), granularity:Cesium.Math.RADIANS_PER_DEGREE*10, material: new Cesium.ImageMaterialProperty({ image:new Cesium.CallbackProperty(() => { let newPic = imageList.shift() imageList.push(newPic) return newPic.image; }, false) }) } });论断:最开始没有设置 granularity的时候,只有2帧率,改成默认值10倍当前有大略60帧率。 ...

November 5, 2021 · 1 min · jiezi

关于cesium:Cesium开发实践

做了大略三个月的基于cesium地图开发的利用场景和大屏;次要想从cesium根本的入门到一些简略的场景交互做一个代码分享。 Cesium是三维地图开发的一个前端gis引擎;反对wtms、影像、模型、地形、歪斜摄影的数据加载。并通过对点线面、材质、视角等图形学常识对它进行一个正式三维场景的一个复现。包含一些最 根本的创立地图、创立点位、数据源组、创立图层、加载gif,相机视角;加载图层、绘制点、线、面,调节情景参数;对接天地图、高德地图、百度地图;事件:点击事件、移除事件、移除事件、拖拽事件弹框:视频弹框、详情弹框、报警弹框轨迹:动静轨迹、轨迹漫游流线图:喷泉、流线图场景:模仿下雪、下雨、雷达图根本工具箱:放大、放大,定位、画线kml、geojson文件转换和加载性能优化常用工具办法 1、根本的创立地图 viewer = new Cesium.Viewer('maps', { animation: false, //是否创立动画小器件,左下角仪表 baseLayerPicker: false, //是否显示图层选择器 fullscreenButton: false, //是否显示全屏按钮 geocoder: false, //是否显示geocoder小器件,右上角查问按钮 homeButton: false, //是否显示Home按钮 infoBox: false, //是否显示信息框 sceneModePicker: false, //是否显示3D/2D选择器 selectionIndicator: false, //是否显示选取指示器组件 timeline: false, //是否显示时间轴 sceneMode: Cesium.SceneMode.SCENE3D, //设定3维地图的默认场景模式:Cesium.SceneMode.SCENE2D、Cesium.SceneMode.SCENE3D、Cesium.SceneMode.MORPHING navigationHelpButton: false, //是否显示右上角的帮忙按钮 scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源 navigationInstructionsInitiallyVisible: false, showRenderLoopErrors: false, //是否显示渲染谬误 shouldAnimate: true,//容许动画 //这个得必须有! })创立的点位:- layer && layer.entities.add({ id: item.id, name: item.name, type: "marker", featureType: type, feature: item.feature, lon: item.lon, lat: item.lat, mapTools: tools,//地图左边按钮 position: Cesium.Cartesian3.fromDegrees(parseFloat(lon), parseFloat(lat), height), billboard: { image: new Cesium.CallbackProperty(() => { return _self.superGif.get_canvas().toDataURL("image/png"); }, false), scale: 1, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, width: 60, height: imageheight }, label: { text: type == "wrj" ? `${item.name}` : "", font: '14pt 微软雅黑', style: Cesium.LabelStyle.FILL_AND_OUTLINE, // backgroundColor: Cesium.Color.YELLOW, // showBackground: true, outlineColor: new Cesium.Color.fromCssColorString("tranparent"), fillColor: new Cesium.Color.fromCssColorString("#fff"), outlineWidth: 5, verticalOrigin: Cesium.VerticalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(-110, -25) }, })创立数据图层- markersLayer = new Cesium.CustomDataSource('marker-layer')- viewer.dataSources.add(markersLayer)创立地图底图图层 viewer.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url: '/static/map/worldimage.jpg' }));加载gif动静图片,须要引入SuperGif插件进行gif转换,再通过Cesium.CallbackProperty一帧帧获取,须要留神得加上dom元素- <img src="/biz/alarm.gif" width="20px" height="20px" ref="gifRef" rel:auto_play="1" rel:rubbable="1" style="position: absolute;z-index: -1;" /> _self.superGif = new SuperGif({ gif: this.$refs.gifRef }); _self.superGif.load(function () { layer && layer.entities.add({ id: item.id, name: item.name, type: "marker", featureType: type, feature: item.feature, lon: item.lon, lat: item.lat, mapTools: tools,//地图左边按钮 position: Cesium.Cartesian3.fromDegrees(parseFloat(lon), parseFloat(lat), height), billboard: { image: new Cesium.CallbackProperty(() => { return _self.superGif.get_canvas().toDataURL("image/png"); }, false), scale: 1, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, width: 60, height: imageheight }, label: { text: type == "wrj" ? `${item.name}` : "", font: '14pt 微软雅黑', style: Cesium.LabelStyle.FILL_AND_OUTLINE, // backgroundColor: Cesium.Color.YELLOW, // showBackground: true, outlineColor: new Cesium.Color.fromCssColorString("tranparent"), fillColor: new Cesium.Color.fromCssColorString("#fff"), outlineWidth: 5, verticalOrigin: Cesium.VerticalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(-110, -25) }, _lng: lon, _lat: lat, _obj: item }) }); } 相机视角(有entity则用viewer,坐标用camera)let heading = viewer.camera.heading, pitch = viewer.camera.pitch, roll = viewer.camera.roll; viewer.flyTo(_self.pickValue, { offset: { heading: 2.990358455542995, // 方向 pitch: -0.5403975721607086,// 歪斜角度 range: 11100 } //定位 let lon = list[0].lon || list[0].longitude, lat = list[0].lat || list[0].latitude; viewer.camera.flyTo(this.mapCenter, 5000);2、加载图层、绘制点、线、面,调节情景参数加载图层天地图超图形式对接 ...

August 17, 2021 · 4 min · jiezi

关于cesium:cesium-流线-飞线-迁徙图-攻防图

该计划借鉴了多个大佬的,把代码理了一遍再整合了一下做了个汇合(算是一个练手的demo)重点这里初始化地球的时候留神下这个参数requestRenderMode(缩小Cesium渲染新帧总工夫并缩小Cesium在应用程序中总体CPU使用率),如果你开启了,那么流线材质就会动一下就不动了,切记!!!!上面是vue组件代码https://segmentfault.com/u/yo... <template> <div class="tole"> <div id="cesiumContainer" style="height: 100%;width: 100%"> </div> </div></template><script>import * as Cesium from 'cesium/Cesium'import widget from 'cesium/Widgets/widgets.css'var viewer = nullexport default { data(){ return{ viewer:null } }, mounted(){ console.log(widget); Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlZGMwM2M2OC02ZGYwLTQ5NzQtYjBkOS1lYTM0MmYxNTZlZTkiLCJpZCI6NjEwNTMsImlhdCI6MTYyNTY0ODgzN30.9B76dtOIBsNmX3laJ5VXFOqt2NlBT-n16j4ppUF8IYA' // viewer = new Cesium.CesiumWidget('cesiumContainer') viewer = new Cesium.Viewer("cesiumContainer",{ animation: false, // 暗藏动画控件 baseLayerPicker: false, // 暗藏图层抉择控件 fullscreenButton: false, // 暗藏全屏按钮 vrButton: false, // 暗藏VR按钮,默认false geocoder: false, // 暗藏地名查找控件 homeButton: false, // 暗藏Home按钮 infoBox: false, // 暗藏点击因素之后显示的信息窗口 sceneModePicker: false, // 暗藏场景模式抉择控件 selectionIndicator: true, // 显示实体对象抉择框,默认true timeline: false, // 暗藏工夫线控件 navigationHelpButton: false, // 暗藏帮忙按钮 scene3DOnly: true, // 每个几何实例将只在3D中出现,以节俭GPU内存 shouldAnimate: true, // 开启动画自动播放 sceneMode: 3, // 初始场景模式 1:2D 2:2D循环 3:3D,默认3 requestRenderMode: false, // 缩小Cesium渲染新帧总工夫并缩小Cesium在应用程序中总体CPU使用率 // 如场景中的元素没有随仿真工夫变动,请思考将设置maximumRenderTimeChange为较高的值,例如Infinity maximumRenderTimeChange: Infinity, //天地图影像 // imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ // url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=39ca2b2b8dc2f3e1e9c3de07f4d4de57", // layer: "tdtBasicLayer", // style: "default", // format: "tiles", // tileMatrixSetID: "GoogleMapsCompatible", // show: true, // maximumLevel: 18 // }) }) this.viewer = viewer //增加天地图标注 // viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({ // url: "http://t0.tianditu.com/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg&tk=39ca2b2b8dc2f3e1e9c3de07f4d4de57", // layer: "tdtAnnoLayer", // style: "default", // format: "tiles", // tileMatrixSetID: "GoogleMapsCompatible", // show: true // })); viewer.cesiumWidget.creditContainer.style.display = "none" //增加线 // var orangeOutlined = viewer.entities.add({ // name: // "Orange line with black outline at height and following the surface", // polyline: { // positions: Cesium.Cartesian3.fromDegreesArrayHeights([ // -75, // 39, // 0, // -125, // 39, // 0, // ]), // width: 5, // material: new Cesium.PolylineOutlineMaterialProperty({ // color: Cesium.Color.ORANGE, // outlineWidth: 2, // outlineColor: Cesium.Color.BLACK, // }), // }, // }); // console.log(orangeOutlined); //增加点位 var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(120.9677706,30.7985748,2.61), point: { color: Cesium.Color.RED, //点位色彩 pixelSize: 10 //像素点大小 }, label : { text : '测试名称', font : '14pt Source Han Sans CN', //字体款式 fillColor:Cesium.Color.BLACK, //字体色彩 backgroundColor:Cesium.Color.AQUA, //背景色彩 showBackground:true, //是否显示背景色彩 style: Cesium.LabelStyle.FILL, //label款式 outlineWidth : 2, verticalOrigin : Cesium.VerticalOrigin.CENTER,//垂直地位 horizontalOrigin :Cesium.HorizontalOrigin.LEFT,//程度地位 pixelOffset:new Cesium.Cartesian2(10,0) //偏移 } }); console.log(entity); //这里通过算法失去曲线 let mm = this.parabola([-75,39,-175,39]) var polyline = new Cesium.PolylineGeometry({ positions: mm, width : 2 }); const instance = new Cesium.GeometryInstance({ geometry: polyline, id: 'flyline', }) //增加至场景 this.viewer.scene.primitives.add( new Cesium.Primitive({ geometryInstances: [instance], appearance: this.getFlylineMaterial(), releaseGeometryInstances: false, compressVertices: false, }) ) }, methods:{ computeFlyline( point1 = [-75, 39], point2 = [-175,39], h = 500000 ) { let flyline = getBSRxyz(...point1, ...point2, h) return flyline // 将数据转换为cesium polyline positions格局 function getBSRxyz(x1, y1, x2, y2, h) { let arr3d = getBSRPoints(x1, y1, x2, y2, h) let arrAll = [] for (let ite of arr3d) { arrAll.push(ite[0]) arrAll.push(ite[1]) arrAll.push(ite[2]) } return Cesium.Cartesian3.fromDegreesArrayHeights(arrAll) } function getBSRPoints(x1, y1, x2, y2, h) { let point1 = [y1, 0] let point2 = [(y2 + y1) / 2, h] let point3 = [y2, 0] let arr = getBSR(point1, point2, point3) let arr3d = [] for (let i = 0; i< arr.length; i++) { let x = ((x2 - x1) * (arr[i][0] - y1)) / (y2 - y1) + x1 arr3d.push([x, arr[i][0], arr[i][1]]) } return arr3d } // 生成贝塞尔曲线 function getBSR(point1, point2, point3) { var ps = [ { x: point1[0], y: point1[1] }, { x: point2[0], y: point2[1] }, { x: point3[0], y: point3[1] } ] // 100 每条线由100个点组成 let guijipoints = CreateBezierPoints(ps, 100) return guijipoints } // 贝赛尔曲线算法 // 参数: // anchorpoints: [{ x: 116.30, y: 39.60 }, { x: 37.50, y: 40.25 }, { x: 39.51, y: 36.25 }] function CreateBezierPoints(anchorpoints, pointsAmount) { var points = [] for (var i = 0; i < pointsAmount; i++) { var point = MultiPointBezier(anchorpoints, i / pointsAmount) points.push([point.x, point.y]) } return points } function MultiPointBezier(points, t) { var len = points.length var x = 0, y = 0 var erxiangshi = function(start, end) { var cs = 1, bcs = 1 while (end > 0) { cs *= start bcs *= end start-- end-- } return cs / bcs } for (var i = 0; i < len; i++) { var point = points[i] x += point.x * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i) y += point.y * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i) } return { x: x, y: y } } }, parabola(twoPoints) { //抛物线绘制 let s = [] let startPoint = [twoPoints[0],twoPoints[1],0]; //终点的经度、纬度 s = s.concat(startPoint) let step = 80; //线的多少,越多则越平滑(但过多浏览器缓存也会占用越多) let heightProportion = 0.125; //最高点和总间隔的比值 let dLon = (twoPoints[2] - startPoint[0])/step; //经度差值 let dLat = (twoPoints[3] - startPoint[1])/step; //纬度差值 let deltaLon = dLon * Math.abs(111000*Math.cos(twoPoints[1])); //经度差(米级) let deltaLat = dLat * 111000; //纬度差(米),1纬度相差约111000米 let endPoint = [0,0,0]; //定义一个端点(前面将进行startPoint和endPoint两点画线) let heigh = (step * Math.sqrt(deltaLon*deltaLon+deltaLat*deltaLat) * heightProportion).toFixed(0)*2; let x2 = (10000*Math.sqrt(dLon*dLon+dLat*dLat)); //小数点扩充10000倍,进步精确度 let a = (heigh/(x2*x2)); function y(x,height) { return height - a*x*x; } for(var i = 1;i <= step; i++){ //逐“帧”画线 endPoint[0] = startPoint[0] + dLon; //更新end点经度 endPoint[1] = startPoint[1] + dLat; //更新end点纬度 let x = x2*(2*i/step-1); //求抛物线函数x endPoint[2] = (y(x,heigh)).toFixed(0)*1; //求end点高度 s = s.concat(endPoint) // end点变为start点 startPoint[0] = endPoint[0]; startPoint[1] = endPoint[1]; startPoint[2] = endPoint[2]; } return Cesium.Cartesian3.fromDegreesArrayHeights(s) }, getFlylineMaterial(){ // 创立材质,在MaterialAppearance中若不增加根底材质,模型将会通明 var material = new Cesium.Material.fromType('Color') material.uniforms.color = Cesium.Color.ORANGE // 飞线成果-飞线距离,宽度2 let fragmentShaderSource = ` varying vec2 v_st; varying float v_width; varying float v_polylineAngle; varying vec4 v_positionEC; varying vec3 v_normalEC; void main() { vec2 st = v_st; // 箭头飞线,宽度 8 float xx = fract(st.s*10.0 + st.t - czm_frameNumber/60.0); if (st.t<0.5) { xx = fract(st.s*10.0 - st.t - czm_frameNumber/60.0); } float r = 0.0; float g = xx; float b = xx; float a = xx; // 飞线边框 if (st.t>0.8||st.t<0.2) { g = 1.0; b = 1.0; a = 0.4; } gl_FragColor = vec4(r,g,b,a); } ` // 自定义材质 const aper = new Cesium.PolylineMaterialAppearance({ material: material, translucent: true, vertexShaderSource: ` #define CLIP_POLYLINE void clipLineSegmentToNearPlane( vec3 p0, vec3 p1, out vec4 positionWC, out bool clipped, out bool culledByNearPlane, out vec4 clippedPositionEC) { culledByNearPlane = false; clipped = false; vec3 p0ToP1 = p1 - p0; float magnitude = length(p0ToP1); vec3 direction = normalize(p0ToP1); float endPoint0Distance = czm_currentFrustum.x + p0.z; float denominator = -direction.z; if (endPoint0Distance > 0.0 && abs(denominator) < czm_epsilon7) { culledByNearPlane = true; } else if (endPoint0Distance > 0.0) { float t = endPoint0Distance / denominator; if (t < 0.0 || t > magnitude) { culledByNearPlane = true; } else { p0 = p0 + t * direction; p0.z = min(p0.z, -czm_currentFrustum.x); clipped = true; } } clippedPositionEC = vec4(p0, 1.0); positionWC = czm_eyeToWindowCoordinates(clippedPositionEC); } vec4 getPolylineWindowCoordinatesEC(vec4 positionEC, vec4 prevEC, vec4 nextEC, float expandDirection, float width, bool usePrevious, out float angle) { #ifdef POLYLINE_DASH vec4 positionWindow = czm_eyeToWindowCoordinates(positionEC); vec4 previousWindow = czm_eyeToWindowCoordinates(prevEC); vec4 nextWindow = czm_eyeToWindowCoordinates(nextEC); vec2 lineDir; if (usePrevious) { lineDir = normalize(positionWindow.xy - previousWindow.xy); } else { lineDir = normalize(nextWindow.xy - positionWindow.xy); } angle = atan(lineDir.x, lineDir.y) - 1.570796327; angle = floor(angle / czm_piOverFour + 0.5) * czm_piOverFour; #endif vec4 clippedPrevWC, clippedPrevEC; bool prevSegmentClipped, prevSegmentCulled; clipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, clippedPrevWC, prevSegmentClipped, prevSegmentCulled, clippedPrevEC); vec4 clippedNextWC, clippedNextEC; bool nextSegmentClipped, nextSegmentCulled; clipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, clippedNextWC, nextSegmentClipped, nextSegmentCulled, clippedNextEC); bool segmentClipped, segmentCulled; vec4 clippedPositionWC, clippedPositionEC; clipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, clippedPositionWC, segmentClipped, segmentCulled, clippedPositionEC); if (segmentCulled) { return vec4(0.0, 0.0, 0.0, 1.0); } vec2 directionToPrevWC = normalize(clippedPrevWC.xy - clippedPositionWC.xy); vec2 directionToNextWC = normalize(clippedNextWC.xy - clippedPositionWC.xy); if (prevSegmentCulled) { directionToPrevWC = -directionToNextWC; } else if (nextSegmentCulled) { directionToNextWC = -directionToPrevWC; } vec2 thisSegmentForwardWC, otherSegmentForwardWC; if (usePrevious) { thisSegmentForwardWC = -directionToPrevWC; otherSegmentForwardWC = directionToNextWC; } else { thisSegmentForwardWC = directionToNextWC; otherSegmentForwardWC = -directionToPrevWC; } vec2 thisSegmentLeftWC = vec2(-thisSegmentForwardWC.y, thisSegmentForwardWC.x); vec2 leftWC = thisSegmentLeftWC; float expandWidth = width * 0.5; if (!czm_equalsEpsilon(prevEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1) && !czm_equalsEpsilon(nextEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1)) { vec2 otherSegmentLeftWC = vec2(-otherSegmentForwardWC.y, otherSegmentForwardWC.x); vec2 leftSumWC = thisSegmentLeftWC + otherSegmentLeftWC; float leftSumLength = length(leftSumWC); leftWC = leftSumLength < czm_epsilon6 ? thisSegmentLeftWC : (leftSumWC / leftSumLength); vec2 u = -thisSegmentForwardWC; vec2 v = leftWC; float sinAngle = abs(u.x * v.y - u.y * v.x); expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0); } vec2 offset = leftWC * expandDirection * expandWidth * czm_pixelRatio; return vec4(clippedPositionWC.xy + offset, -clippedPositionWC.z, 1.0) * (czm_projection * clippedPositionEC).w; } vec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious, out float angle) { vec4 positionEC = czm_modelViewRelativeToEye * position; vec4 prevEC = czm_modelViewRelativeToEye * previous; vec4 nextEC = czm_modelViewRelativeToEye * next; return getPolylineWindowCoordinatesEC(positionEC, prevEC, nextEC, expandDirection, width, usePrevious, angle); } attribute vec3 position3DHigh; attribute vec3 position3DLow; attribute vec3 prevPosition3DHigh; attribute vec3 prevPosition3DLow; attribute vec3 nextPosition3DHigh; attribute vec3 nextPosition3DLow; attribute vec2 expandAndWidth; attribute vec2 st; attribute float batchId; varying float v_width; varying vec2 v_st; varying float v_polylineAngle; varying vec4 v_positionEC; varying vec3 v_normalEC; void main() { float expandDir = expandAndWidth.x; float width = abs(expandAndWidth.y) + 0.5; bool usePrev = expandAndWidth.y < 0.0; vec4 p = czm_computePosition(); vec4 prev = czm_computePrevPosition(); vec4 next = czm_computeNextPosition(); float angle; vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev, angle); gl_Position = czm_viewportOrthographic * positionWC; v_width = width; v_st.s = st.s; v_st.t = st.t; // v_st.t = czm_writeNonPerspective(st.t, gl_Position.w); v_polylineAngle = angle; vec4 eyePosition = czm_modelViewRelativeToEye * p; v_positionEC = czm_inverseModelView * eyePosition; // position in eye coordinates //v_normalEC = czm_normal * normal; // normal in eye coordinates } `, fragmentShaderSource: fragmentShaderSource }) return aper; }, }}</script><style scope lang="scss">.tole{ width: 100%; height: 100%;}</style>这里有两个曲线算法computeFlyline和parabola,任选其一即可其中一个来自于https://www.cnblogs.com/s3131...另一个忘了(原作者能够分割我) ...

July 9, 2021 · 7 min · jiezi

关于Cesium:cesium-vue2配置

装置Cesium npm i cesium --save 配置webpack.base.conf.js 减少别名( cesium: path.resolve(__dirname, '../node_modules/cesium/Source') ) resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), cesium: path.resolve(__dirname, '../node_modules/cesium/Source') } },module 增加属性 unknownContextCritical: false,否则会报上面这个error:require function is used in a way in which dependencies cannot be statically module: {..... unknownContextCritical: false, .....}webpack.dev.conf.js plugins: [.... // Copy Cesium Assets, Widgets, and Workers to a static directory new CopyWebpackPlugin([ { from: path.join('node_modules/cesium/Source', '../Build/Cesium/Workers'), to: 'Workers' } ]), new CopyWebpackPlugin([ { from: path.join('node_modules/cesium/Source', 'Assets'), to: 'Assets' } ]), new CopyWebpackPlugin([ { from: path.join('node_modules/cesium/Source', 'Widgets'), to: 'Widgets' } ]), new webpack.DefinePlugin({ // Define relative base path in cesium for loading assets CESIUM_BASE_URL: JSON.stringify('') }),...]webpack.dev.conf.js ...

May 29, 2021 · 2 min · jiezi

关于Cesium:cesium基础使用分享

html点位的实现从2d地图转到cesium,对文档一顿输入后,发现cesium居然没有html点位绘制的api,例如cesium的label只能绘制文字点位,billboard绘制图片点位,根本无法达到html字符串那种灵活性。 几经搜寻后,发现大家都是css定位来模仿的,也就是创立一个div元素插入到页面,而后绝对于cesium的canvas来进行绝对定位,这里的外围就是将你的指标经纬度转换为css定位的地位。 然而下面还有一个致命的问题,那就是你的div元素是应用的css定位,当地图滑动后,你的css定位马上就露馅了,他是无奈跟地图的经纬度实时改正的。 下面的实时改正操作就须要你来实现,也就是实时将经纬度转换为css定位单位(点位一多,性能可想而已)。 代码稍后补充。

May 27, 2021 · 1 min · jiezi