提示:Cesium中提供两类API:
(1)面向图形开发人员的底层API,通常称为“Primitive API”。该API暴露最小限度的抽象,使用图形学术语,具有很大的灵活性,需要具有图形学编程的知识;
(2)高级别的数据驱动的API,称为“Entity API”。该API使用一致性设计的、高级别的对象来管理一组相关性的可视化对象,其底层使用Primitive API;
几何图形与外观
我们可以通过Primitive API来操控几何图形及其外观,或者绘制各种特殊的形状。需要先得到Scene对象,然后在其上添加Primitive对象:
1. var viewer = new Cesium.Viewer('cesiumContainer');
2. var scene = viewer.scene;
3.
4. scene.primitives.add(new Cesium.RectanglePrimitive({
5. //绘制矩形
6. rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
7. material : Cesium.Material.fromType('Dot') //设置材质
8. }));
Primitive由两个部分组成:
1. (1)几何形状(Geometry):定义了Primitive的结构,例如三角形、线条、点等
2. (2)外观(Appearance):定义Primitive的着色(Sharding),包括GLSL(OpenGL着色语言,OpenGL Shading Language)顶点着色器和片段着色器( vertex and fragment shaders),以及渲染状态(render state)
Cesium支持以下几何图形:
几何图形 |
说明 |
BoxGeometry |
立方体 |
BoxOutlineGeometry |
仅有轮廓的立方体 |
CircleGeometry |
圆形或者拉伸的圆形 |
CircleOutlineGeometry |
只有轮廓的圆形 |
CorridorGeometry |
走廊:沿着地表的多段线,且具有一定的宽度,可以拉伸到一定的高度 |
CorridorOutlineGeometry |
只有轮廓的走廊 |
CylinderGeometry |
圆柱、圆锥或者截断的圆锥 |
CylinderOutlineGeometry |
只有轮廓的圆柱、圆锥或者截断的圆锥 |
EllipseGeometry |
椭圆或者拉伸的椭圆 |
EllipseOutlineGeometry |
只有轮廓的椭圆或者拉伸的椭圆 |
EllipsoidGeometry |
椭球体 |
EllipsoidOutlineGeometry |
只有轮廓的椭球体 |
RectangleGeometry |
矩形或者拉伸的矩形 |
RectangleOutlineGeometry |
只有轮廓的矩形或者拉伸的矩形 |
PolygonGeometry |
多边形,可以具有空洞或者拉伸一定的高度 |
PolygonOutlineGeometry |
只有轮廓的多边形 |
PolylineGeometry |
多段线,可以具有一定的宽度 |
SimplePolylineGeometry |
简单的多段线 |
PolylineVolumeGeometry |
多段线柱体 |
PolylineVolumeOutlineGeometry |
只有轮廓的多段线柱体 |
SphereGeometry |
球体 |
SphereOutlineGeometry |
只有轮廓的球体 |
WallGeometry |
墙 |
WallOutlineGeometry |
只有轮廓的墙 |
使用Geometry和Appearance具有以下优势:
1. (1)性能:绘制大量Primitive时,可以将其合并为单个Geometry以减轻CPU负担、更好的使用GPU。合并Primitive由web worker线程执行,UI保持响应性
2. (2)灵活性:Geometry与Appearance解耦,两者可以分别进行修改
3. (3)低级别访问:易于编写GLSL顶点、片段着色器、使用自定义的渲染状态
同时,具有以下劣势:
1. (1)需要编写更多地代码
2. (2)需要对图形编程有更多的理解,特别是OpenGL的知识
使用来Geometry、Appearance改写上面的例子,代码为:
1. var viewer = new Cesium.Viewer('cesiumContainer');
2. var scene = viewer.scene;
3. //GeometryInstance是Geometry的一个容器
4. var instance = new Cesium.GeometryInstance({
5. geometry : new Cesium.RectangleGeometry({
6. rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
7. vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
8. })
9. });
10.//使用抽象的Primitive而不是RectanglePrimitive
11. scene.primitives.add(new Cesium.Primitive({
12. geometryInstances : instance,
13. //使用该外观,可以使矩形覆盖在地球表面,或者悬浮一定的高度
14. appearance : new Cesium.EllipsoidSurfaceAppearance({
15. material : Cesium.Material.fromType('Dot')
16. })
17. }));
合并几何图形(Combing Geometries)
合并多个GeometryInstances为一个Primitive可以极大的提高性能,下面的例子创建了2592一颜色各异的矩形,覆盖整个地球 :
1. var viewer = new Cesium.Viewer( 'cesiumContainer' );
2. var scene = viewer.scene;
3.
4. var instances = [];
5.
6. for ( var lon = -180.0; lon < 180.0; lon += 5.0 )
7. {
8. for ( var lat = -90.0; lat < 90.0; lat += 5.0 )
9. {
10. instances.push( new Cesium.GeometryInstance( {
11. geometry : new Cesium.RectangleGeometry( {
12. rectangle : Cesium.Rectangle.fromDegrees( lon, lat, lon + 5.0, lat + 5.0 )
13. } ),
14. attributes : {
15. color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.fromRandom( {
16. alpha : 0.5
17. } ) )
18. }
19. } ) );
20. }
21. }
22.
23. scene.primitives.add( new Cesium.Primitive( {
24. geometryInstances : instances, //合并
25. //某些外观允许每个几何图形实例分别指定某个属性,例如:
26. appearance : new Cesium.PerInstanceColorAppearance()
27. } ) );
选取几何图形(Picking)
即使多个 GeometryInstance被合并为单个Primitive,让然可以独立的被访问。我们可以为每一个GeometryInstance指定一个id,并且可以通过Scene.pick来判断该实例是否被选取:
1. var viewer = new Cesium.Viewer( 'cesiumContainer' );
2. var scene = viewer.scene;
3.
4. var instance = new Cesium.GeometryInstance( {
5. geometry : new Cesium.RectangleGeometry( {
6. rectangle : Cesium.Rectangle.fromDegrees( -100.0, 30.0, -90.0, 40.0 )
7. } ),
8. id : 'rectangle-1',
9. attributes : {
10. color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.RED )
11. }
12.} );
13.
14.scene.primitives.add( new Cesium.Primitive( {
15. geometryInstances : instance,
16. appearance : new Cesium.PerInstanceColorAppearance()
17. } ) );
18. 重点重点重点重点重点重点
19. var handler = new Cesium.ScreenSpaceEventHandler( scene.canvas );
20.//设置单击事件的处理句柄
21. handler.setInputAction( function( movement )
22.{
23. var pick = scene.pick( movement.position );
24. if ( Cesium.defined( pick ) && ( pick.id === 'rectangle-1' ) )
25. {
26. console.log( '矩形被选取' );
27. }
28.}, Cesium.ScreenSpaceEventType.LEFT_CLICK );
几何图形实例(Geometry Instances)
上面的例子中,我们已经用到了GeometryInstances,注意GeometryInstance与Geometry的关系:前者是后者的容器,多个Instance可以共用一个Geometry,并且可以通过GeometryInstances.modelMatrix属性提供不同position、scale、rotate等位置、缩放、旋转信息。例如,下面的例子使用同一个Geometry绘制了两个Instance,一个位于另一个的上方:
1. var viewer = new Cesium.Viewer( 'cesiumContainer' );
2. var scene = viewer.scene;
3.
4. var ellipsoidGeometry = new Cesium.EllipsoidGeometry( {
5. vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
6. radii : new Cesium.Cartesian3( 300000.0, 200000.0, 150000.0 )//三轴半径
7. } );
8. //下方的实例
9. var cyanEllipsoidInstance = new Cesium.GeometryInstance( {
10. geometry : ellipsoidGeometry,
11. modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees( -100.0, 40.0 ) ), new Cesium.Cartesian3( 0.0, 0.0, 150000.0 ) ),
12. attributes : {
13. color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.CYAN )
14. }
15. } );
16.//上方的实例
17. var orangeEllipsoidInstance = new Cesium.GeometryInstance( {
18. geometry : ellipsoidGeometry,
19. modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees( -100.0, 40.0 ) ), new Cesium.Cartesian3( 0.0, 0.0, 450000.0 ) ),
20. attributes : {
21. color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.ORANGE )
22. }
23. } );
24.
25. scene.primitives.add( new Cesium.Primitive( {
26. geometryInstances : [
27. cyanEllipsoidInstance, orangeEllipsoidInstance
28. ],
29. appearance : new Cesium.PerInstanceColorAppearance( {
30. translucent : false,
31. closed : true
32. } )
33. } ) );
更新单个GeometryInstance的属性
在添加到Primitive中以后,让然可以修改几何图形的某些属性:
1. (1)颜色:如果Primitive设置了PerInstanceColorAppearance外观,则可以修改ColorGeometryInstanceAttribute类型的颜色
2. (2)可见性:任何实例可以修改可见性
示例代码:
1. var viewer = new Cesium.Viewer( 'cesiumContainer' );
2. var scene = viewer.scene;
3.
4. var circleInstance = new Cesium.GeometryInstance( {
5. geometry : new Cesium.CircleGeometry( {
6. center : Cesium.Cartesian3.fromDegrees( -95.0, 43.0 ),
7. radius : 250000.0,
8. vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
9. } ),
10. attributes : {
11. color : Cesium.ColorGeometryInstanceAttribute.fromColor( new Cesium.Color( 1.0, 0.0, 0.0, 0.5 ) ),
12. show : new Cesium.ShowGeometryInstanceAttribute( true ) //显示或者隐藏
13. },
14. id : 'circle'
15. } );
16.var primitive = new Cesium.Primitive( {
17. geometryInstances : circleInstance,
18. appearance : new Cesium.PerInstanceColorAppearance( {
19. translucent : false,
20. closed : true
21. } )
22.} );
23. scene.primitives.add( primitive );
24.
25. //定期修改颜色
26.setInterval( function()
27. {
28. var attributes = primitive.getGeometryInstanceAttributes( 'circle' );//获取某个实例的属性集
29. attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue( Cesium.Color.fromRandom( {
30. alpha : 1.0
31. } ) );
32.}, 2000 );
外观(Appearances)
Primitive由两个重要部分组成:几何图形实例、外观,一个Primitive只能有一个外观,而可以有多个实例。几何图形定义了结构,外观定义了每个像素被如何着色,外观可能使用材质(Material)。这些对象的关系如下图所示:
Cesium支持下表列出的外观:
外观 |
说明 |
MaterialAppearance |
支持各种Geometry类型的外观,支持使用材质来定义着色 |
EllipsoidSurfaceAppearance |
MaterialAppearance的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(vertex attributes)的计算 |
PerInstanceColorAppearance |
让每个实例使用自定义的颜色来着色 |
PolylineMaterialAppearance |
支持使用材质来着色多段线 |
PolylineColorAppearance |
使用每顶点或者每片段(per-vertex or per-segment)的颜色来着色多段线 |
外观定义了需要在GPU上执行的完整的GLSL顶点、片段着色器,通常不需要修改这一部分,除非需要定义自己的外观。
外观还定义了完整的render state,用于在绘制Primitive时控制GPU的状态,可以直接或者通过高层API来定义render state:
1. //下面的外观可用于定义一个Viewer不可进入的不透明盒子
2. var appearance = new Cesium.PerInstanceColorAppearance( {
3. translucent : false,
4. closed : true
5. } );
6. //下面的代码效果同上
7. var translucent = new Cesium.PerInstanceColorAppearance( {
8. renderState : {
9. depthTest : {
10. enabled : true
11. },
12. cull : {
13. enabled : true,
14. face : Cesium.CullFace.BACK
15. }
16. }
17. } );
一旦外观被创建,其render state就不可再变,但是其材质是可以替换的。另外Primitive的外观也是不可修改的。
大部分外观具有flat、faceForward属性,可以间接的控制GLSL着色器:
1. (1)flat:扁平化着色,不考虑光线的作用
2. (2)faceForward:布尔值,控制光照效果
Geometry与Appearance的兼容性
需要注意,不是所有外观和所有几何图形可以搭配使用,例如EllipsoidSurfaceAppearance与WallGeometry就不能搭配,原因是后者是垂直于地表的。
即使外观与几何图形兼容,它们还必须有匹配的顶点格式(vertex formats)——即几何图形必须具有外观可以作为输入的数据格式,在创建Geometry时可以提供VertexFormat。
为了简便,可以让Geometry计算所有顶点属性(vertexattributes),以使之适用于任何外观,但这样做效率较差:
1. var geometry = new Cesium.RectangleGeometry( {
2. vertexFormat : Cesium.VertexFormat.ALL
3. } );
而如果我们使用外观EllipsoidSurfaceAppearance,其实只需要知道位置:
1. var geometry = new Ceisum.RectangleGeometry( {
2. vertexFormat : Ceisum.VertexFormat.POSITION_ONLY
3. } );
大部分外观具有vertexFormat属性或者VERTEX_FORMAT静态常量,创建形状时只需要使用这些顶点格式即可:
1. var geometry = new Ceisum.RectangleGeometry( {
2. vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT
3. } );
4.
5. var geometry2 = new Ceisum.RectangleGeometry( {
6. vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT
7. } );
8.
9. var appearance = new Ceisum.MaterialAppearance();
10.var geometry3 = new Ceisum.RectangleGeometry( {
11. vertexFormat : appearance.vertexFormat
12.} );