Cesium(三) 几何图形与外观

                           几何图形与外观

我们可以通过Primitive API来操控几何图形及其外观,或者绘制各种特殊的形状。需要先得到Scene对象,然后在其上添加Primitive对象:

[javascript] view plain copy
  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 改写上面的例子,代码为:

[javascript] view plain copy
  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一颜色各异的矩形,覆盖整个地球 :

[javascript] view plain copy
  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来判断该实例是否被选取:

[javascript] view plain copy
  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,一个位于另一个的上方:

[javascript] view plain copy
  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)可见性:任何实例可以修改可见性

示例代码:

[javascript] view plain copy
  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类型的外观,支持使用材质来定义着色
EllipsoidSurfaceAppearanceMaterialAppearance的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(vertex attributes)的计算
PerInstanceColorAppearance让每个实例使用自定义的颜色来着色
PolylineMaterialAppearance支持使用材质来着色多段线
PolylineColorAppearance使用每顶点或者每片段(per-vertex or per-segment )的颜色来着色多段线

外观定义了需要在GPU上执行的完整的GLSL顶点、片段着色器,通常不需要修改这一部分,除非需要定义自己的外观。

外观还定义了完整的render state,用于在绘制Primitive时控制GPU的状态,可以直接或者通过高层API来定义render state:

[javascript] view plain copy
  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计算所有顶点属性(vertex attributes),以使之适用于任何外观,但这样做效率较差:

[javascript] view plain copy
  1. var geometry = new Cesium.RectangleGeometry( {  
  2.     vertexFormat : Cesium.VertexFormat.ALL  
  3. } );  
而如果我们使用外观EllipsoidSurfaceAppearance,其实只需要知道位置:

[javascript] view plain copy
  1. var geometry = new Ceisum.RectangleGeometry( {  
  2.     vertexFormat : Ceisum.VertexFormat.POSITION_ONLY  
  3. } );  
大部分外观具有vertexFormat属性或者VERTEX_FORMAT 静态常量,创建形状时只需要使用这些顶点格式即可:

[javascript] view plain copy
  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. } );  

此外,两个形状必须具有匹配的vertexFormat,才能被合并到一个Primitive中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值