Cesium | Primitive图元介绍及与Entity对比

前言

在之前的文章中,我们大部分使用的添加实体的方式都是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
//下面的外观可用于定义一个Viewer不可进入的不透明盒子
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的优势了,所以在加载几何体时二者都有优有劣,需要根据具体情况进行选择。


Cesium | Primitive图元介绍及与Entity对比
https://moewang0321.github.io/2021/06/17/Cesium中Primitive图元介绍及与Entity对比/
作者
Moe Wang
发布于
2021年6月17日
许可协议