前言
在之前的文章中,我们大部分使用的添加实体的方式都是entity添加,而在性能优化中我们提到了primitive添加的方式,entity在本文就不多做介绍了,本文主要介绍一下primitive相关知识。
什么是Primitive
首先我们在Cesium API文档中搜索primitive,看文档中对Primitive类的介绍,翻译过来大致如下:
图元代表场景中的几何体。 几何可以来自单个 GeometryInstance,也可以来自实例数组,即使geometry 来自不同的几何类型。图元将geometry 实例与描述完整着色的 Appearance 相结合,包括 Material 和 RenderState。 粗略地说,geometry 实例定义了结构和位置,appearance 定义了视觉特征。 解耦geometry 和appearance 允许我们混合和匹配它们中的大部分,并相互独立地添加新的geometry 或appearance 。
将多个实例组合成一个原语称为批处理,可显着提高静态数据的性能。 实例可以单独挑选; Scene#pick 返回它们的 GeometryInstance#id。 使用 PerInstanceColorAppearance 等每个实例的外观,每个实例也可以具有唯一的颜色。
Geometry可以在 web worker 或主线程上创建和批处理。
通过阅读我们可以知道,primitive主要由两部分组成:Geometry和Appearance。
Geometry主要定义了primitive的几何结构,而Appearance主要负责定义primitive的着色,包括GLSL顶点着色器、片段着色器和渲染状态。
我们可以通过Primitive API来操控几何图形及其外观,绘制各种形状。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | var instance = new Cesium.GeometryInstance({   geometry : new Cesium.EllipseGeometry({       center : Cesium.Cartesian3.fromDegrees(-100.0, 20.0),       semiMinorAxis : 500000.0,       semiMajorAxis : 1000000.0,       rotation : Cesium.Math.PI_OVER_FOUR,       vertexFormat : Cesium.VertexFormat.POSITION_AND_ST   }),   id : 'object returned when this instance is picked and to get/set per-instance attributes' }); scene.primitives.add(new Cesium.Primitive({   geometryInstances : instance,   appearance : new Cesium.EllipsoidSurfaceAppearance({     material : Cesium.Material.fromType('Checkerboard')   }) }));
 
  | 
 
Geometry
在Cesium中,支持以下几种Geometry几何图形
| 几何图形 | 
说明 | 
| 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 Instances - 几何图形实例
在前边的示例代码中,我们已经用到了它,它相当于Geometry的容器,而多个Instance可以公用一个Geomotry并利用GeometryInstance.modelMatrix提供多种属性信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | var geometry = Cesium.BoxGeometry.fromDimensions({   vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL,   dimensions : new Cesium.Cartesian3(1000000.0, 1000000.0, 500000.0) }); var instanceBottom = new Cesium.GeometryInstance({   geometry : geometry,   modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(     Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 1000000.0), new Cesium.Matrix4()),   attributes : {     color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)   },   id : 'bottom' }); var instanceTop = new Cesium.GeometryInstance({   geometry : geometry,   modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(     Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 3000000.0), new Cesium.Matrix4()),   attributes : {     color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)   },   id : 'top' });
 
  | 
 
Combing Geometries - 合并几何图形
我们可以合并多个Instance为一个Primitive,提高我们的性能。
1 2 3 4 5 6
   | var instances = [Instance1, Instance2, Instance3, ……]; scene.primitives.add( new Cesium.Primitive( {     geometryInstances : instances,           appearance : new Cesium.PerInstanceColorAppearance({translucent : false,closed : true}) } ) );
 
  | 
 
更新单个Instance属性
在添加到Primitive后,我们仍然可以通过Id获取指定Instance并修改其属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | var circleInstance = new Cesium.GeometryInstance( {     geometry : new Cesium.CircleGeometry( {         center : Cesium.Cartesian3.fromDegrees( -95.0, 43.0 ),         radius : 250000.0,         vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT     } ),     attributes : {         color : Cesium.ColorGeometryInstanceAttribute.fromColor( new Cesium.Color( 1.0, 0.0, 0.0, 0.5 ) ),         show : new Cesium.ShowGeometryInstanceAttribute( true )      },     id : 'circle' } ); var primitive = new Cesium.Primitive( {     geometryInstances : circleInstance,     appearance : new Cesium.PerInstanceColorAppearance( {         translucent : false,         closed : true     } ) } ); scene.primitives.add( primitive );
  var attributes = primitive.getGeometryInstanceAttributes( 'circle' ); attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue( Cesium.Color.fromRandom( {     alpha : 1.0 } ) );
 
  | 
 
Appearance
Cesium支持以下列出的Appearance
| 外观 | 
描述 | 
| MaterialAppearance | 
支持各种Geometry类型的外观,支持使用材质来定义着色。支持材料描述阴影。 | 
| EllipsoidSurfaceAppearance | 
MaterialAppearance的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(vertex attributes)的计算。和Material Appearance一样,就像一个多边形,并且使用这个假设来通过程序上计算许多顶点属性来节省内存。 | 
| PerInstanceColorAppearance | 
让每个实例使用自定义的颜色来着色,使用每个实例的颜色来遮蔽每个实例。 | 
| PolylineMaterialAppearance | 
支持使用材质来着色多段线。支持材料遮蔽Polyline。 | 
| PolylineColorAppearance | 
使用每顶点或者每片段(per-vertex or per-segment )的颜色来着色多段线—使用每顶点或每段着色来遮蔽折线 | 
Appearance定义了需要在GPU上执行的GLSL着色器,这部分一般只有在自定义外观时需要修改。
render state用来在绘制Primitive的时候控制GPU状态,一旦外观被创建,render state就不能再改变了,但是我们可以修改其材质。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   |  var appearance = new Cesium.PerInstanceColorAppearance( {     translucent : false,     closed : true } );
  var translucent = new Cesium.PerInstanceColorAppearance( {     renderState : {         depthTest : {             enabled : true         },         cull : {             enabled : true,             face : Cesium.CullFace.BACK         }     } } );
 
  | 
 
Primitive与Entity对比
看过上边对Primitive相关接口的用法,我们会有这样的疑惑:entity调用方便,封装完美,为什么还要使用Primitive?区别就是记载的效率问题。Primitve更接近webGL的底层,没有entity一样的附加属性,加载时效率会更高。在前文性能优化中已经体现出Primitive的优势了,所以在加载几何体时二者都有优有劣,需要根据具体情况进行选择。