cesium学习
一、Cesium 初始化
C e s i u m W i d g e t 才是核心类 \color{red} CesiumWidget 才是核心类 CesiumWidget才是核心类
定义assessToken
Cesium.Ion.defaultAccessToken='在Cesium 官网中申请的token'
实例化cesium
ArcGIS 影像图层
const esri = new Cesium.ArcGisMapServerImageryProvider({
url:"https:services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
enablePickFeatures: false,
})
const viewer=new Cesium.Viewer('cesiumContainer',
{ baseLayerPicker:false,图层选择控件隐藏
timeline:false,时间轴控件
animation:false,动画控件
geocoder:false,搜索控件
homeButton:false,主页控件
sceneModePicker:false,投影方式按钮
baseLayerPicker:false,选择图层控件
navigationHelpButton:false,帮助手势控件
fullscreenButton:false,全屏控件
imageryProvider:esri, 自定义图层,默认的是谷歌的影像图层
terrainProvider:Cesium.createWorldTerrain({
requestWaterMask:true 水面特效
requestVertexNormal:true 地形法线,实现地势凹凸效果
}
) 地形图层}) 创建有各种按钮和组件的地球
const viewer=new Cesium.cesiumWidget('cesiumContainer')创建纯地球
1.clock用来记录时间,毕竟三维场景需要进行动态展示,需要通过时间来确定某一帧的绘制内容
2.container则是构造函数的参数,也就是传入的div。
3.canvas则是在container上构建的Canvas类的对象,可以据此获取WebGL绘制的画笔。
4.screenSpaceEventHandler则是对Canvas对象上各种鼠标的交互事件的封装,方便传递给三维场景。之后可以据此改变相机姿态等。
5.scene则承载着整个三维场景中的对象。
二 scene 详解
Scene中有一些内置的图元对象:地球(globe)、skybox(天空盒)、sun(太阳)、moon(月亮)等等;另外还有两个用来由用户自行控制存放对象的数组:primitives和groundPrimitives。groundPrimitives创建的对象完全贴地,用户感知不到对象的存在。
三 primitives
图元是Cesium用来绘制三维对象的一个独立的结构,图元类有:Globe、Model、Primitive、Bilboardcolection、ViewportQuad等。
Globe绘制的是全球地形,它需要两个东西,一个是地形高程信息,另外一个是影像图层,也就是地球的表皮。影像图层可以叠加多个,但是地形高程只能有一个。整个地形的绘制也是渐进式的,即视线看到的地方才会去调度相关的地形高程信息,找到对应位置的地形影像贴上。然而Globe只是一个图元。由此可见一个图元可以相当复杂。
需要注意的地方:
1. 图元没有基类,但是所有的图元都会有 u p d a t e 的数 \color{red}1 .图元没有基类,但是所有的图元都会有update的数 1.图元没有基类,但是所有的图元都会有update的数
2. p r i m i t i v e 类直译过来是图元的意思,但是它不是基类,只是图元的一种,起作用是用来绘制各种几何体。 \color{red}2.primitive类直译过来是图元的意思,但是它不是基类,只是图元的一种,起作用是用来绘制各种几何体。 2.primitive类直译过来是图元的意思,但是它不是基类,只是图元的一种,起作用是用来绘制各种几何体。
3. 图元是一类对象绘制的集合,可以包含多个 W e b G l 的 d r a w c a l l 。 \color{red} 3.图元是一类对象绘制的集合,可以包含多个WebGl的drawcall。 3.图元是一类对象绘制的集合,可以包含多个WebGl的drawcall。
1.cesium 加载模型
let longitude =114;
let.latitude =36;
let height =0;
let position =Cesiun.Cartesian3.fronDegrees(longitude, latitude, height);
let heading =cesium.Math.toRadians(0);
let pitch=cesiun.Math.toRadians(0);
let roll=cesium.Math.toRadians(0);
let hpr =new cesium.HeadingPitchRoll(heading, pitch, roll);
let orientation =cesiun.Transforms.headingPitchRollQuaternion(position, hpr).
通过 scene加载模型 scene.primitives.add增加一个图元
model= scene.primitives.add(Cesium.Model.fromGltf({
url :url,
modelMatrix : orientation
minimumPixelsize :128
}));
通过 entity加载模型
varmodel. viewer.entities.add({
name:"第一个模型",
description:"这是我们第二个测试”
position: position,
orientation:orientation,
nodel:{url:"./sampleData/models/cesiumMilkTruck/cesiumMilkTruck.glb"
}):
2.Cesium 创建billboard
(1)单个billboard
1.用viewer 添加实体方式
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
billboard: {
image: "../images/Cesium_Logo_overlay.png", default: undefined
show: true, default
pixelOffset: new Cesium.Cartesian2(0, -50), default: (0, 0) 位置便宜量
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), default
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
alignedAxis: Cesium.Cartesian3.ZERO, default
width: 100, default: undefined
height: 25, default: undefined
pixelOffsetScaleByDistance:new Cesium.NearFarScale(1.0e3,1,1.5e6,0), 根据远近设置偏移量
},
});
//2.用 primitive.add 方式
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),
pixelOffset: new Cesium.Cartesian2(0, -50), default: (0, 0)
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), default
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
alignedAxis: Cesium.Cartesian3.ZERO, default
width: 100, default: undefined
height: 25, default: undefined
sizeInMeters: false, default
});
}
(2)多个billboard一起加载 BillboardCollection
const scene = viewer.scene;
let billboardCount = 100489; 创建billboard的数量
const gridSize = Math.sqrt(billboardCount); 开平方
billboardCollection = scene.primitives.add(
new Cesium.BillboardCollection({
scene: scene,
})
);
const position = new Cesium.Cartographic(
longitude,
latitude,
10000.0
);
for (let y = 0; y < gridSize; ++y) {
for (let x = 0; x < gridSize; ++x) {
const longitude = Cesium.Math.lerp(
e.west,
e.east,
x / (gridSize - 1)
);
const latitude = Cesium.Math.lerp(
e.south,
e.north,
y / (gridSize - 1)
);
const position = new Cesium.Cartographic(
longitude,
latitude,
10000.0
);
billboardCollection.add({
position: scene.globe.ellipsoid.cartographicToCartesian(position),直角坐标系
image: "../images/facility.gif",
scale: 1.0,
});
}
}
(3) point billboards
可以将canvas 画的图案作为 billboard的url
const canvas = document.createElement("canvas");
canvas.width = 16;
canvas.height = 16;
const context2D = canvas.getContext("2d");
context2D.beginPath();
context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true);
context2D.closePath();
context2D.fillStyle = "rgb(255, 255, 255)";
context2D.fill();
const billboards = scene.primitives.add(
new Cesium.BillboardCollection()
);
billboards.add({
imageId: "custom canvas point",
image: canvas,
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
color: Cesium.Color.RED,
scale: 0.5,
});
billboards.add({
imageId: "custom canvas point",
image: canvas,
position: Cesium.Cartesian3.fromDegrees(-80.5, 35.14),
color: Cesium.Color.BLUE,
});
billboards.add({
imageId: "custom canvas point",
image: canvas,
position: Cesium.Cartesian3.fromDegrees(-80.12, 25.46),
color: Cesium.Color.LIME,
scale: 2,
});
}
(4) 相对某一点为原点,东向为x 轴,北向为z轴建立坐标系( 有多种建立坐标的方式,具体查询官网 reference)
const center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
billboards.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
center
);
3.Cesium 创建labels&Cesium.LabelCollection
同billboards
const label=viewer.entities.add({
id:'label',
position:Cesium.Cartesian3.fromDegrees(120,30),
label:{
text:'Cesium',
fillColor:Cesium.Color.YELLOWGREEN,
showBackground:true,
backgroundColor:new Cesium.Color(255,255,0),
}
})
4.Cesium 创建点 point
(1) 单个点
viewer
const point2=viewer.entities.add({
id:'point',
position:Cesium.Cartesian3.fromDegrees(120,30),
point:{
pixelSize:10,
color:Cesium.Color.RED
}
})
primitives
const pointPrimitives = scene.primitives.add(
new Cesium.PointPrimitiveCollection()
);
pointPrimitives.add({
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
show: true, default
color: Cesium.Color.SKYBLUE, default: WHITE
pixelSize: 10, default: 1
outlineColor: Cesium.Color.YELLOW, default: TRANSPARENT
outlineWidth: 3, default: 0
});
}
(1) 多个点 pointprimative
const pointPrimitives = scene.primitives.add(
new Cesium.PointPrimitiveCollection()
);
pointPrimitives.add({
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
show: true, default
color: Cesium.Color.SKYBLUE, default: WHITE
pixelSize: 10, default: 1
outlineColor: Cesium.Color.YELLOW, default: TRANSPARENT
outlineWidth: 3, default: 0
});
}
pointPrimitives.add({
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
show: true, default
color: Cesium.Color.SKYBLUE, default: WHITE
pixelSize: 10, default: 1
outlineColor: Cesium.Color.YELLOW, default: TRANSPARENT
outlineWidth: 3, default: 0
});
}
5.Cesium 创建折线
const polyline=viewer.entities.add({
id:'polyline',
polyline:{
positions:Cesium.Cartesian3.fromDegreesArray([
120,30,
120,40
]),
width:5,
material:Cesium.Color.RED
}
})
6.Cesium 创建多边形
const polygon=viewer.entities.add({
id:'polygon',
polygon:{
hierarchy:Cesium.Cartesian3.fromDegreesArray([
120,25,
121,24,
121,25.2
]),
height:1000,高度
extrudedHeight:2000, 拉伸
outline:true,是否显示外线
outlineColor:Cesium.Color.WHITE,
fill:false,是否填充
material:Cesium.Color.RED
}
})
7.Cesium 创建 盒子
const box=viewer.entities.add({
id:'box',
position:Cesium.Cartesian3.fromDegrees(120,30),
box:{
dimensions:new Cesium.Cartesian3(100000,100000,100000),
material:Cesium.Color.BLUEVIOLET
}
})
8.Cesium 创建 椭圆
const ellipse=viewer.entities.add({
id:'ellipse',
position:Cesium.Cartesian3.fromDegrees(125,20),
ellipse:{
semiMinorAxis:100000,短半轴
semiMajorAxis:200000,长半轴
material:Cesium.Color.BLUE
}
})
墙实体
viewer.entities.add({
name: "Green wall from surface with outline",
wall: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
-107.0,
43.0,
100000.0,
-97.0,
43.0,
100000.0,
-97.0,
40.0,
100000.0,
-107.0,
40.0,
100000.0,
-107.0,
43.0,
100000.0,
]),
material: Cesium.Color.GREEN,
outline: true,
},
});
9.Cesium 创建 组合实体
const group=viewer.entities.add({
id:'group',
position:Cesium.Cartesian3.fromDegrees(120,30,100),
billboard:{
image:'/src/assets/meiyangyang.jpg',
scale:0.1,
color :Cesium.Color.RED
},
label:{
text:'Cesium',
fillColor:Cesium.Color.YELLOWGREEN,
showBackground:true,
backgroundColor:new Cesium.Color(255,255,0),
},
line:{
positions:Cesium.Cartesian3.fromDegreesArrayHeights([
120,30,100,
120,40,100
]),
width:5,
material:Cesium.Color.AQUA
}
}
)
10 Cesium地形影像加载
(1) 地形的加载
地形效果:https://sandcastle.cesium.com/?src=Terrain.html
(2) 影像的加载(类似不同的地图表皮,给地球贴图)
可在初始化时加载,也可在后面单独加载
const esri = new Cesium.ArcGisMapServerImageryProvider({
url:"https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
enablePickFeatures: false,
})
//初始化加载
const viewer=new Cesium.Viewer('cesiumContainer',{
imageryProvider:esri, //自定义图层,默认的是谷歌的影像图层
})
//单独加载
const layers = viewer.scene.imageryLayers;
const blackMarble = Cesium.ImageryLayer.fromProviderAsync(
Cesium.IonImageryProvider.fromAssetId(3812)
);
blackMarble.alpha = 0.5;
blackMarble.brightness = 2.0;
layers.add(blackMarble);
11.primitives
使用 Collection()创建效率更高,但可设置的东西较少,通过GeometryInstance 创建可定制化更高
(1)Polyline
a.SimplePolylineGeometry:画线,效率更高,无法设置宽度
(development 的例子 官网不展示,需要自己下载Cesium 起服务)
http://localhost:8080/Apps/Sandcastle/index.html?src=development%2FSimple%20Polyline.html&label=Development
b.GroundPolylineGeometry:贴着地形的折线
http://localhost:8080/Apps/Sandcastle/index.html?src=development%2FGround%20Polyline%20Material.html&label=Development
12.3D Tiles
用于 加载倾斜摄影、3dmax 等模型
(1) 3dtiles 的加载
//通过内置ID加载
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(75343)
viewer.scene.primitives.add(tileset);
//通过url 加载
tileset = await Cesium.Cesium3DTileset.fromUrl(
"../../SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json"
);
viewer.scene.primitives.add(tileset);
(2)3dtiles 的拾取
(3)3dtiles 的裁切
(4)3dtiles inspector
(5)3dtiles 的style控制
(6)classificationPrimitive
附着到3dmax 模型上,改变整体颜色
示例地址:https://sandcastle.cesium.com/?src=3D%20Tiles%20Photogrammetry%20Classification.html
const classificationTilesetUrl =
"../../SampleData/Cesium3DTiles/Classification/Photogrammetry/tileset.json";
// A b3dm tileset used to classify the photogrammetry tileset
const classificationTileset = await Cesium.Cesium3DTileset.fromUrl(
classificationTilesetUrl,
{
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
}
);
classificationTileset.style = new Cesium.Cesium3DTileStyle({
color: "rgba(255, 0, 0, 0.5)",
});
viewer.scene.primitives.add(classificationTileset);
13.Appearance
(1) PerInstanceColorAppearance(常用)
可用于所有创建的实体,用于配合实体attributes 给物体加颜色属性
const boxGeometryInstance = new Cesium.GeometryInstance({
geometry: boxGeometry,
modelMatrix: boxModelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(1.0, 0.0, 0.0, 0.5)
),
},
});
// Add the geometry instance to primitives.
scene.primitives.add(
new Cesium.Primitive({
geometryInstances: boxGeometryInstance, //可以是一个数组,多个实体用一个材质
appearance: new Cesium.PerInstanceColorAppearance({
closed: true,
}),
})
);
(1) MaterialAppearance
可用于所有创建的实体,支持给物体贴图,设置复杂样式
primitives.add(
new Cesium.Primitive({
geometryInstances: wallInstance,
appearance: new Cesium.MaterialAppearance({
material: Cesium.Material.fromType("Checkerboard", {
repeat: new Cesium.Cartesian2(20.0, 6.0),
}),
}),
})
);
14.Material
示例:http://localhost:8080/Apps/Sandcastle/index.html?src=Materials.html&label=Development
只有 M a t e r i a l A p p e a r a n c e , P o l y l i n e M a t e r i a l A p p e a r a n c e 可以设置 M a t e r i a l \color{red}只有MaterialAppearance,PolylineMaterialAppearance 可以设置Material 只有MaterialAppearance,PolylineMaterialAppearance可以设置Material
//给物体加颜色
// Create a color material with fromType:
polygon.material = Cesium.Material.fromType('Color');
polygon.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
// Create the default material:
polygon.material = new Cesium.Material();
// Create a color material with full Fabric notation:
polygon.material = new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: new Cesium.Color(1.0, 1.0, 0.0, 1.0)
}
}
});
//图片贴图
primitive.appearance.material = new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: "../images/Cesium_Logo_Color.jpg",
},
},
});
15.Camera和Scene中的其他函数使用
(1)Camera
//初始化相机,设置相机位置
const position=Cesium.Cartesian3.fromDegrees(110,20,20000)
viewer.camera.setView({
destination:position,//设置相机位置
orientation:{ //默认 (0,-90,0) 设置相机角度
heading:Cesium.Math.toRadians(0),
pitch:Cesium.Math.toRadians(0),
roll:Cesium.Math.toRadians(0)
}
})
//相机飞到制定位置
viewer.camera.flyTo({
destination:position,//设置相机目的地
orientation:{ //默认 (0,-90,0) 设置相机角度 //不设置时默认朝着正北方向
heading:Cesium.Math.toRadians(0),
pitch:Cesium.Math.toRadians(0),
roll:Cesium.Math.toRadians(0)
},
duration:3,//单位 s
complete: function () { //完成之后的事件,可以省略
setTimeout(function () {
camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
-73.98585975679403,
40.75759944127251,
186.50838555841779
),
orientation: {
heading: Cesium.Math.toRadians(200.0),
pitch: Cesium.Math.toRadians(-50.0),
},
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
});
}, 1000);
},
})
//lookAt 将视角固定在设置的点位上,可以选择视角,但不能改变位置
const position2=Cesium.Cartesian3.fromDegrees(110,20)
viewer.camera.lookAt(
position2,//设置相机目的地
new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(0),
Cesium.Math.toRadians(-90),
20000
),
)
// fly to Rectangle
const west = -77.0;
const south = 38.0;
const east = -72.0;
const north = 42.0;
const rectangle = Cesium.Rectangle.fromDegrees(
west,
south,
east,
north
);
viewer.camera.setView({
destination: rectangle,
});
//相机移动添加事件
const camera = viewer.camera;
removeStart = camera.moveStart.addEventListener(function () {
viewChanged.style.display = "block";
});
removeEnd = camera.moveEnd.addEventListener(function () {
viewChanged.style.display = "none";
});
// 相机改变添加事件
let i = 0;
removeChanged = viewer.camera.changed.addEventListener(function (
percentage //相机变化幅度
) {
++i;
cameraChanged.innerText = `Camera Changed: ${i}, ${percentage.toFixed(
6
)}`;
cameraChanged.style.display = "block";
});
//改变相机坐标系,源坐标系为地球球心
const center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
// View in east-north-up frame
const camera = viewer.camera;
camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z;
camera.lookAtTransform(
transform,
new Cesium.Cartesian3(-120000.0, -120000.0, 120000.0)
);
// Show reference frame. Not required.
referenceFramePrimitive = scene.primitives.add(
new Cesium.DebugModelMatrixPrimitive({
modelMatrix: transform,
length: 100000.0,
})
);
View in ICRF //设置相机坐标系绕着地球旋转
function icrf(scene, time) {
if (scene.mode !== Cesium.SceneMode.SCENE3D) {
return;
}
const icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time);
if (Cesium.defined(icrfToFixed)) {
const camera = viewer.camera;
const offset = Cesium.Cartesian3.clone(camera.position);
const transform = Cesium.Matrix4.fromRotationTranslation(
icrfToFixed
);
camera.lookAtTransform(transform, offset);
}
}
viewer.camera.flyHome(0);
clock.multiplier = 3 * 60 * 60;
scene.postUpdate.addEventListener(icrf);
scene.globe.enableLighting = true;
//查看相机位置
1.camera.positionWC 相机相对于地球球心位置(笛卡尔坐标)
2.camera.position 相机相对于当前坐标系位置(笛卡尔坐标)
2.camera.positionCartographic相机相对于当前坐标系位置(经纬度)
camera.transform 相机当前坐标系矩阵
Scene的api文档查看
https:/cesium.com/downloads/cesiumjs/releases/1.57/Build/Documentation/Scene.html?classfilter=Scene1
(1)调试类函数
scene.debugShowFramesPerSecond=true //显示帧率
/debugShowGlobeDepth/…
(2) WebGL渲染状态 logarithmicDepthBuffer/mode
(3)事件preRender/postUpdate/postRender/preUpdate/renderError
cartesianToCanvasCoordinates(position) //三维坐标转屏幕坐标
clampToHeightMostDetailed(cartesians, objectsToExclude, width) //求最精细高度
drillPick(windowPosition, limit, width, height) 从相机到屏幕上一点画一条射线,返回射线上的所有物体
var pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));
pick(windowPosition, width, height) 获取某坐标的物体
// On mouse over, color the feature yellow.
handler.setInputAction(function(movement) {
var feature = scene.pick(movement.endPosition);
if (feature instanceof Cesium.Cesium3DTileFeature) {
feature.color = Cesium.Color.YELLOW;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
pickPosition(windowPosition, result) 获取某点三维坐标
(4)环境对象 sun/moon/skyBox/…
(6)后处理相关示例
调试用的函数 debugShowFramesPerSecond debugShowDepthFrustum debugShowGlobeDepth
15.viewer&entity
dataSource:数据源,创建一组实体。
customDataSource 用户自定义dataSource
Viewer/Entities的作用:
1.方便创建直观的对象,同时做到性能优化(bilboard、point等)
2.提供一些方便使用的函数:flyTo/zoomTo
3.赋予Entity对象时间这个属性,对象具备动态特性/Primitive不具备
4.提供一些U(homeButton/sceneModePicker/projectionPicker/baseLayerPicker)
5.大量的快捷方式,camera等末必是好事。
6.Datasource模式来加载大规模数据:Geojson
viewer.flyTo(target,options) target 为一个对象 异步函数,会自动等待对象加载完再飞过去
zoomTo与flyTo 类似,没有中间过程
16.Property的使用
参考此文章: https://blog.csdn.net/Handsome2013/article/details/104871664