三维地球可视化从入门到进阶 - 实体 Entity、图形 Primitive 详解
本文为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!
这篇文章是Cesium 三维地球可视化从入门到进阶专栏的第五篇。主要是对Cesium中创建图形常用的两种方法:Entity、Primitive做详解。
截至目前,Cesium基础知识基本上都讲解的差不多了,如果你对基础的一些使用方式还是不了解的话,可以参考前面几节内容。
??三维地球可视化从入门到进阶 - 基础详解??三维地球可视化从入门到进阶 - Viewer、Scene、Camera、加载第三方影像、地形服务??三维地球可视化从入门到进阶 - 坐标系统??三维地球可视化从入门到进阶 - 鼠标键盘事件、相机事件、数据加载事件、场景加载事件??三维地球可视化从入门到进阶 - 实体 Entity、图形 Primitive 详解后续的文章将会以分享案例的形式分享,如果你也喜欢三维地球可视化, 记得一定要关注我。
Entity实体简介实体(entity)是Cesium中自带的创建图形的方法,通过该方法可以在场景中创建点、线、面、多边形、立方体、圆等基本图形。 截止目前为止,Cesium中支持17种实体:
实体名称类型描述图例billboardBillboardGraphics广告牌,可以自定义为图片或文字boxBoxGraphics盒子corridorCorridorGraphicscorridor直译为走廊,实际上是将多个点相连形成的一种实体。cylinderCylinderGraphics圆柱体,可以通过设置上下半径生成锥体ellipseEllipseGraphics椭圆ellipsoidEllipsoidGraphics椭球体labelLabelGraphics标签modelModelGraphics模型,主要用于加载 glTF 模型tilesetCesium3DTilesetGraphics瓦片集合,主要用于加载 3D tiles 模型pathPathGraphics路径,实际上是将大量的点连起来绘制的一种线条实体planePlaneGraphics平面pointPointGraphics点polygonPolygonGraphics多边形polylinePolylineGraphics折线polylineVolumePolylineVolumeGraphics折线体rectangleRectangleGraphics矩形wallWallGraphics墙简单示例下面以创建一个盒子为例,介绍创建一个实体的基本方法:
varboxEntity=viewer.entities.add({
id:'1234abcdxxxx',//实体的ID,具有唯一性
name:'Nameoftheentity',//实体的名称,可以不唯一
position:Cesium.Cartesian3.fromDegrees(-107.0,40.0,300000.0),//实体的坐标
box:{
dimensions:newCesium.Cartesian3(400000.0,300000.0,500000.0),
material:Cesium.Color.RED.withAlpha(0.5),
outline:true,
outlineColor:Cesium.Color.BLACK
}
});
viewer.zoomTo(boxEntity)//视角定位到实体
其效果如下:
创建一个实体一般包含以下几个基本属性:
id(非必须):标识该实体的 ID,具有唯一性;name(非必须):标识该实体的名称,可以不唯一;position(必须):指定该实体存在的位置;实体的类型及其属性(必须):如上面例子中的box,不同的实体表达的图形不一样,其所需属性也不同,下面会依次介绍不同实体的创建方法。其中id和name属性即使不指定,也会成功创建实体并且不会报错,但是若缺少位置信息,程序虽不会报错,但是无法成功创建该实体。
盒子 box下面是创建一个盒子的完整代码:
varboxEntity=viewer.entities.add({
id:'123123123',//盒子的ID
name:'Nameoftheentity',//盒子的名称
position:Cesium.Cartesian3.fromDegrees(-107.0,40.0,300000.0),//盒子的位置
box:{
dimensions:newCesium.Cartesian3(400000.0,300000.0,500000.0),//尺寸
distanceDisplayCondition:newCesium.DistanceDisplayCondition(0,2000000),//可视距离
material:Cesium.Color.RED.withAlpha(0.5),//材质
fill:true,//材质填充
outline:true,//显示轮廓线
outlineColor:Cesium.Color.BLACK,//轮廓线颜色
outlineWidth:1.0,//轮廓线宽度
show:true,//显示盒子
}
});
各个属性的释义如下:
尺寸:dimensionsdimensions属性所需的参数为一个笛卡尔空间直角坐标系的对象,Cartesian3(x, y, z)其中的三个参数分别代表笛卡尔空间直角坐标系的的x、y、z,可以简单理解为设置盒子的长宽高,如下图:
可视距离:distanceDisplayConditiondistanceDisplayCondition表示实体的可视距离,所需的参数为一个DistanceDisplayCondition对象,DistanceDisplayCondition(near, far)的两个参数表达该实体的可视距离,near表示可视的最近距离,far表示可视的最远距离,如下面伪代码,表示在 0 到 2000000 米的范围内该实体可见:
box:{
distanceDisplayCondition:newCesium.DistanceDisplayCondition(0,2000000),//可视距离为0到2000000米之间
}
效果如图,该实体随着镜头的拉伸而显示和隐藏:
材质:materialmaterial属性用于设置盒子表面的材质,默认值为白色,在上面的例子中将盒子的材质设置为了 0.5 透明度的红色材质:
box:{
material:Cesium.Color.RED.withAlpha(0.5),//材质为半透明的红色
}
材质填充:fillfill属性的参数为布尔值,用于控制盒子的面是否用材质填充,默认值为true,所以在图中可见盒子的面都是半透明红色的,若将其置为false:
box:{
fill:flase,//取消材质填充
}
其效果图如下,只剩下盒子轮廓线:
轮廓线:outlineoutline属性的参数为布尔值,用于控制盒子是否显示轮廓线,默认值为true,当把outline的值置为false时,则会隐藏盒子的轮廓线:
box:{
outline:flase,//隐藏盒子轮廓线
}
其效果图如下:
轮廓线颜色:outlineColoroutlineColor属性的参数为 Cesium 颜色值,其默认值为黑色,可以修改为其他颜色:
box:{
outlineColor:Cesium.Color.PINK,//将盒子轮廓线颜色修改为粉色
}
轮廓线宽度:outlineWidthoutlineWidth属性的参数为数值类型,用于控制轮廓线的宽度,默认值为 1.0,可以将其线条宽度加粗:
box:{
outlineWidth:10,//将盒子轮廓线宽度加粗
}
显示和隐藏:showshow属性的参数为布尔值,用于控制盒子的显示和隐藏,默认值为true,将其置为false后盒子就隐藏了:
box:{
show:false,//将盒子隐藏
}
点point下面是创建一个点的完整代码:
varpointEntity=viewer.entities.add({
position:Cesium.Cartesian3.fromDegrees(-107.0,40.0,0.0),//点的位置
point:{
color:Cesium.Color.RED,//颜色
outlineColor:Cesium.Color.PINK,//轮廓线颜色
outlineWidth:5,//轮廓线宽度
pixelSize:20,//点的大小
distanceDisplayCondition:newCesium.DistanceDisplayCondition(10,10000),//可视距离
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,//相对高度
scaleByDistance:newCesium.NearFarScalar(100,1,10000,15),//距离缩放
translucencyByDistance:newCesium.NearFarScalar(100,0.4,200,0.8),//距离透明
show:true,//显示和隐藏
}
})
效果图如下:
各个属性的释义如下:
颜色:colorcolor属性的参数为 Cesium 颜色值,其默认值为白色,可以修改为其他颜色:
point:{
color:Cesium.Color.BLACK,//将点的颜色置为黑色
}
轮廓线颜色:outlineColoroutlineColor属性的参数为 Cesium 颜色值,其默认值为黑色,可以修改为其他颜色:
point:{
outlineColor:Cesium.Color.PINK,//将点的颜色置为粉色
}
轮廓线宽度:outlineWidthoutlineWidth属性的参数为 Cesium 颜色值,其默认值为 0,单位为像素:
point:{
outlineWidth:10,//将点的轮廓线宽度置为10
}
点的大小:pixelSizepixelSize用于控制点的大小,单位为像素,其默认值为 1:
point:{
pixelSize:20,//将点的像素大小置为20
}
可视距离:distanceDisplayConditiondistanceDisplayCondition表示实体的可视距离,所需的参数为一个DistanceDisplayCondition对象,DistanceDisplayCondition(near, far)的两个参数表达该实体的可视距离,near表示可视的最近距离,far表示可视的最远距离,如下面伪代码,表示在 0 到 2000000 米的范围内该实体可见:
point:{
distanceDisplayCondition:newCesium.DistanceDisplayCondition(0,2000000),//可视距离为0到2000000米之间
}
相对高度:heightReferenceheightReference指的是实体距离地形的相对高度,它有三个可选的值:
可选值值的类型描述Cesium.HeightReference.NONENumber绝对高度,即在position中设置的高度就是最后的显示高度Cesium.HeightReference.CLAMP_TO_GROUNDNumber浮于地表,无论在position中设置怎么样的高度值,点的位置始终浮于地表,即固定在地形上Cesium.HeightReference.RELATIVE_TO_GROUNDNumber相对于地形的高度,即在position中设置的高度值是在地形高度的基础上进行计算的距离缩放:scaleByDistancescaleByDistance属性用于指定点在不同的可视距离下放大或缩小的倍数,如下面代码:
point:{
scaleByDistance:newCesium.NearFarScalar(100,2,10000,15),//100米以下放大2倍,10000米以上放大15倍
}
NearFarScalar(near, nearValue, far, farValue)对象接收四个参数:
参数值值的类型默认值描述nearNumber0.0最近距离nearValueNumber0.0小于最近距离时,放大或缩小的倍数farNumber1.0最远距离farValueNumber0.0大于最远距离时,放大或缩小的倍数其效果图如下,随着距离的变化,到临界值时其点的大小也发生改变:
距离透明:translucencyByDistancescaleByDistance属性用于指定点在不同的可视距离下的透明度,如下面代码:
point:{
translucencyByDistance:newCesium.NearFarScalar(100,0.2,10000,0.8),//100米以下透明度为0.2,10000米以上透明度为0.8
}
参数依旧是NearFarScalar不过参数的意义稍有区别:
参数值值的类型默认值描述nearNumber0.0最近距离nearValueNumber0.0小于最近距离时的透明度farNumber1.0最远距离farValueNumber0.0大于最远距离时的透明度其效果图如下,随着距离的变化,到临界值时其点的透明度也发生变化:
Primitive图形简介图形(Primitive)是Cesium中更加高阶的创建图形的方法,那么相对低阶的方法就是使用实体(Entity)定义一个图形。当创建一个图形时,两者的流程都是定义实体的尺寸大小和定义实体的材质外观。图形(Primitive)由两部分组成:
几何形状(Geometry):定义了 Primitive 的结构,例如三角形、线条、点等;外观(Appearance ):定义 Primitive 的着色(Sharding),包括 GLSL(OpenGL 着色语言,OpenGL Shading Language)顶点着色器和片段着色器( vertex and fragment shaders),以及渲染状态(render state)。图形(Primitive)的优劣但图形(Primitive)相较于实体(Entity)有如下优势:
性能:绘制大量 Primitive 时,可以将其合并为单个 Geometry 以减轻 CPU 负担、更好的使用 GPU。合并 Primitive 由 web worker 线程执行,UI 保持响应性;灵活性:Geometry 与 Appearance 解耦,两者可以分别进行修改;低级别访问:易于编写 GLSL 顶点、片段着色器、使用自定义的渲染状态 。同时,图形(Primitive)有如下劣势:
需要编写更多地代码;需要对图形编程有更多的理解,特别是 OpenGL 的知识。Cesium 中支持的图形图形名称类型描述BoxGeometry
BoxOutlineGeometryBoxGeometry
BoxOutlineGeometry盒子
仅有轮廓线的盒子CircleGeometry
CircleOutlineGeometryCircleGeometry
CircleOutlineGeometry圆形
仅有轮廓线的圆形CoplanarPolygonGeometry
CoplanarPolygonOutlineGeometryCoplanarPolygonGeometry
CoplanarPolygonOutlineGeometry共面多边形
仅有轮廓线的共面多边形CorridorGeometry
CorridorOutlineGeometryCorridorGeometry
CorridorOutlineGeometry走廊
仅有轮廓线的走廊CylinderGeometry
CylinderOutlineGeometryCylinderGeometry
CylinderOutlineGeometry圆柱
仅有轮廓线的圆柱EllipseGeometry
EllipseOutlineGeometryEllipseGeometry
EllipseOutlineGeometry椭圆
仅有轮廓线的椭圆EllipsoidGeometry
EllipsoidOutlineGeometryEllipsoidGeometry
EllipsoidOutlineGeometry椭球体
仅有轮廓线的椭球体FrustumGeometry
FrustumOutlineGeometryFrustumGeometry
FrustumOutlineGeometry截锥体
仅有轮廓线的截锥体GroundPolylineGeometryGroundPolylineGeometry地面多段线PlaneGeometry
PlaneOutlineGeometryPlaneGeometry
PlaneOutlineGeometry平面
仅有轮廓线的平面PolygonGeometry
PolygonOutlineGeometryPolygonGeometry
PolygonOutlineGeometry折线
仅有轮廓线的折线PolylineVolumeGeometry
PolylineVolumeOutlineGeometryPolylineVolumeGeometry
PolylineVolumeOutlineGeometry折线体
仅有轮廓线的折线体RectangleGeometry
RectangleOutlineGeometryRectangleGeometry
RectangleOutlineGeometry矩形
仅有轮廓线的矩形SimplePolylineGeometrySimplePolylineGeometry简单折线SphereGeometry
SphereOutlineGeometrySphereGeometry
SphereOutlineGeometry球体
仅有轮廓线的球体WallGeometry
WallOutlineGeometryWallGeometry
WallOutlineGeometry墙
仅有轮廓线的墙简单示例在地球上绘制出青色背景上有黄色点的矩形图形:
简单的创建方法viewer.scene.primitives.add(newCesium.RectanglePrimitive({
rectangle:Cesium.Rectangle.fromDegrees(-100.0,20.0,-90.0,30.0),//绘制矩形
material:Cesium.Material.fromType('Dot')//设置材质
}))
使用几何形状和外观的创建方法//GeometryInstance是Geometry的一个容器
constinstance=newCesium.GeometryInstance({
geometry:newCesium.RectangleGeometry({
rectangle:Cesium.Rectangle.fromDegrees(-100.0,20.0,-90.0,30.0),
vertexFormat:Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
})
})
//使用抽象的Primitive而不是RectanglePrimitive
constrectanglePrimitive=viewer.scene.primitives.add(newCesium.Primitive({
geometryInstances:instance,
//使用该外观,可以使矩形覆盖在地球表面,或者悬浮一定的高度
appearance:newCesium.EllipsoidSurfaceAppearance({
material:Cesium.Material.fromType('Dot')
})
}))
合并集合图形合并多个GeometryInstances为一个Primitive可以极大的提高性能,下面的例子创建了 2592 一颜色各异的矩形,覆盖整个地球:
创建代码如下:
letinstances=[]//用于存放所有geometry
for(letlon=-180.0;lon180.0;lon+=5.0){
for(letlat=-90.0;lat90.0;lat+=5.0){
instances.push(newCesium.GeometryInstance({
geometry:newCesium.RectangleGeometry({
rectangle:Cesium.Rectangle.fromDegrees(lon,lat,lon+5.0,lat+5.0)
}),
attributes:{
color:Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({
alpha:0.5
}))
}
}
}
viewer.scene.primitives.add(newCesium.Primitive({
geometryInstances:instances,//合并
//某些外观允许每个几何图形实例分别指定某个属性,例如:
appearance:newCesium.PerInstanceColorAppearance()
}))
图形拾取即使多个GeometryInstance被合并为单个Primitive,仍然可以单独访问。我们可以为每一个GeometryInstance指定一个id,并且可以通过scene.pick来判断该实例是否被选取:
letinstance=newCesium.GeometryInstance({
geometry:newCesium.RectangleGeometry({
rectangle:Cesium.Rectangle.fromDegrees(-100.0,30.0,-90.0,40.0)
}),
id:'rectangle-1',
attributes:{
color:Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
}
})
viewer.scene.primitives.add(newCesium.Primitive({
geometryInstances:instance,
appearance:newCesium.PerInstanceColorAppearance()
}))
lethandler=newCesium.ScreenSpaceEventHandler(viewer.scene.canvas);
//设置单击事件的处理句柄
handler.setInputAction(function(movement){
letpick=viewer.scene.pick(movement.position)
if(Cesium.defined(pick)(pick.id==='rectangle-1')){
alert('矩形被选取');
}
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
更新单个 Instance 的属性在添加到Primitive中以后,让然可以修改几何图形的某些属性:
颜色:如果Primitive设置了PerInstanceColorAppearance外观,则可以修改ColorGeometryInstanceAttribute类型的颜色;可见性:任何实例可以修改可见性。代码如下:
letcircleInstance=newCesium.GeometryInstance({
geometry:newCesium.CircleGeometry({
center:Cesium.Cartesian3.fromDegrees(-95.0,43.0),
radius:250000.0,
vertexFormat:Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
attributes:{
color:Cesium.ColorGeometryInstanceAttribute.fromColor(newCesium.Color(1.0,0.0,0.0,0.5)),
show:newCesium.ShowGeometryInstanceAttribute(true)//显示或者隐藏
},
id:'circle'
})
letprimitive=newCesium.Primitive({
geometryInstances:circleInstance,
appearance:newCesium.PerInstanceColorAppearance({
translucent:false,
closed:true
})
})
viewer.scene.primitives.add(primitive)
//定期修改颜色
setInterval(function(){
letattributes=primitive.getGeometryInstanceAttributes('circle')//获取某个实例的属性集
attributes.color=Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({
alpha:1.0
}))
},1000)
外观(Appearances)Primitive由两个重要部分组成:几何图形实例、外观,一个Primitive只能有一个外观,而可以有多个实例。几何图形定义了结构,外观定义了每个像素被如何着色,外观可能使用材质(Material)。Cesium 支持下表列出的外观:
外观名称类型描述MaterialAppearanceMaterialAppearance支持各种 Geometry 类型的外观,支持使用材质来定义着色EllipsoidSurfaceAppearanceEllipsoidSurfaceAppearanceMaterialAppearance 的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(vertex attributes)的计算PerInstanceColorAppearancePerInstanceColorAppearance让每个实例使用自定义的颜色来着色PolylineMaterialAppearancePolylineMaterialAppearance支持使用材质来着色多段线PolylineColorAppearancePolylineColorAppearance使用每顶点或者每片段(per-vertex or per-segment )的颜色来着色多段线外观定义了需要在 GPU 上执行的完整的 GLSL 顶点、片段着色器,通常不需要修改这一部分,除非需要定义自己的外观。外观还定义了完整的render state,用于在绘制Primitive时控制 GPU 的状态,可以直接或者通过高层 API 来定义render state:
//下面的外观可用于定义一个Viewer不可进入的不透明盒子
letappearance=newCesium.PerInstanceColorAppearance({
translucent:false,
closed:true
})
//下面的代码效果同上
lettranslucent=newCesium.PerInstanceColorAppearance({
renderState:{
depthTest:{
enabled:true
},
cull:{
enabled:true,
face:Cesium.CullFace.BACK
}
}
})
一旦外观被创建,其render state就不可再变,但是其材质是可以替换的。另外Primitive的外观也是不可修改的。大部分外观具有flat、faceForward属性,可以间接的控制 GLSL 着色器:
flat:扁平化着色,不考虑光线的作用;faceForward:布尔值,控制光照效果。Geometry 与 Appearance 的兼容性需要注意,不是所有外观和所有几何图形可以搭配使用,例如EllipsoidSurfaceAppearance与WallGeometry就不能搭配,原因是后者是垂直于地表的。即使外观与几何图形兼容,它们还必须有匹配的顶点格式(vertex formats)—— 即几何图形必须具有外观可以作为输入的数据格式,在创建Geometry时可以提供VertexFormat。为了简便,可以让Geometry计算所有顶点属性(vertex attributes),以使之适用于任何外观,但这样做效率较差:
letgeometry=newCesium.RectangleGeometry({
vertexFormat:Cesium.VertexFormat.ALL
})
而如果我们使用外观EllipsoidSurfaceAppearance,其实只需要知道位置:
letgeometry=newCeisum.RectangleGeometry({
vertexFormat:Ceisum.VertexFormat.POSITION_ONLY
})
大部分外观具有vertexFormat属性或者VERTEX_FORMAT静态常量,创建形状时只需要使用这些顶点格式即可:
letgeometry=newCeisum.RectangleGeometry({
vertexFormat:Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT
})
letgeometry2=newCeisum.RectangleGeometry({
vertexFormat:Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT
})
letappearance=newCeisum.MaterialAppearance()
letgeometry3=newCeisum.RectangleGeometry({
vertexFormat:appearance.vertexFormat
})
此外,两个形状必须具有匹配的vertexFormat,才能被合并到一个Primitive中。
?? 这篇文章是Cesium 三维地球可视化从入门到进阶专栏的第五篇文章,主要是对Cesium中创建图形常用的两种方法:Entity、Primitive做详解。
?? 在后续的文章中, 将会分享更多的实践案例,如果你也对三维可视化比较感兴趣的话,欢迎关注我一起学习
??Github 仓库地址:https://github.com/xushanpei/Cesium_Study_Cases
写在最后公众号:前端开发爱好者专注分享web前端相关技术文章、视频教程资源、热点资讯等,如果喜欢我的分享,给 ???? 点一个赞?? 或者 ?关注都是对我最大的支持。
大家好,我 xy,是一名前端 ?? 爱好:瞎折腾
如果你也是一名瞎折腾的前端欢迎加我微信交流哦...
?? 一定要点我[1]
[1]https://juejin.cn/pin/7040966241468547109:https://juejin.cn/pin/7040966241468547109
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线