Bootstrap

Cesium: Primitive vs Entity

Primitive vs Entity

Entity

Cesium Sandcastle: Variety of available entities

更高级别的数据驱动 API,它使用一致性设计的、高级别对象来管理一组相关性的可视化对象,其底层也是使用的 primitive

多个类型的实体可以结合使用(如 billboard + label),但同一种实体不能存在多个(如多个 billboard 只能分别创建 entity 实例)。

⚠️ 当在场景中实例化并加载上万个 entity 时,加载速率和性能往往没有有效组织 primitive 来的高。

// i.e. 加载图标
viewer.entities.add({
  position: position,
  billboard: {
    image: "./static/blueCamera.png",
    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
  },
});

Cesium 支持的 Entity

实体类型说明
BillboardGraphics点,广告牌,图片标注
LabelGraphics点,文字标注
PointGraphics点,或者填充颜色的圆
CorridorGraphics走廊:沿着地表的多段线(垂直于表面的折线),且具有一定的宽度,可以拉伸到一定的高度
CylinderGraphics圆柱、圆锥或者截断的圆锥
EllipseGraphics椭圆或者拉伸的椭圆
EllipsoidGraphics椭球体
RectangleGraphics矩形或者正柱体
PlaneGraphics平面
PolygonGraphics多边形,可以具有空洞或者拉伸一定的高度
PathGraphics多段线,以路径方式呈现,可随时间移动
PolylineGraphics多段线,可以具有一定的宽度
PolylineVolumeGraphics多段线柱体
BoxGraphics立方体
WallGraphics
ModelGraphicsgltf 3d 模型
Cesium3DTilesetGraphics3d tiles tileset

Primitive

Cesium Sandcastle: Variety of available primitives

主要由两部分组成:Geometry(几何结构) 和 Appearance(GLSL 顶点着色器、片段着色器和渲染状态)

面向图形开发人员的底层 API,暴露最小限度的抽象,更多使用图形学术语,具有更大的灵活性。

图元(Primitive)代表场景中的几何体。 几何可以来自单个 GeometryInstance,也可以来自实例数组,即 geometry 来自不同的几何类型。图元将 geometry 实例与描述完整着色的 appearance 相结合,包括 Material 和 RenderState。
粗略地说,geometry 实例定义了结构和位置,appearance 定义了视觉特征。 解耦 geometry 和 appearance,允许我们混合和匹配它们中的大部分,并相互独立地添加新的 geometry 或 appearance 。
将多个实例组合成一个原语称为批处理,可显着提高静态数据的性能。 实例可以单独挑选,Scene#pick 返回它们的 GeometryInstance#id。使用 PerInstanceColorAppearance 设定实例的外观,每个实例可以具有唯一的颜色。
Geometry 可以在 web worker 或主线程上创建和批处理

其具有以下优势:

  1. 性能:绘制大量 Primitive 时,可以将其合并为单个 Geometry,减轻 CPU 负担,更好使用 GPU。
  2. 灵活:GeometryAppearance 解耦,两者可独立修改。

同样的,使用 primitive 就意味着需要编写更多代码,以及对图形学深入的了解。

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')
  })
}));

内置几何集合(collection)

⚠️ 为方便使用,cesium 内部提供了一部分常用的可渲染集合对象,在无法满足的情况下再考虑自定义构造

// i.e. 加载多个图标
this.billboards = viewer.scene.primitives.add(
  new Cesium.BillboardCollection()
);

for(let i = 0; i < 10000; i++) {
  this.billboards.add({
    position: position,
    image:  require("./images/blueCamera.png"),
    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
  });
}
Cesium 内部提供的可渲染图形集合
图形集合说明
BillboardCollection图标。为了获得最佳性能,最好选择几个系列,每个系列都有许多图形,而不是许多系列,每个系列只有零星的图形。组织图形,使具有相同更新频率的图形位于同一集合中,如不更改的图形应位于一个集合中,每一帧都变化的图形应该在另一个集合中。
LabelCollection文字。为了获得最佳性能,参考 BillboardCollection
PointPrimitiveCollection点。为了获得最佳性能,参考 BillboardCollection
PolylineCollection多段线。为了获得最佳性能,参考 BillboardCollection
CloudCollection云特效

Geometry - 几何体

Cesium 支持的 Geometry
几何图形轮廓几何图形类别说明
BoxGeometryBoxOutlineGeometry立方体立方体
CircleGeometryCircleOutlineGeometry圆形圆形或者拉伸的圆形,圆圈或挤压圆
CorridorGeometryCorridorOutlineGeometry走廊走廊:沿着地表的多段线(垂直于表面的折线),且具有一定的宽度,可以拉伸到一定的高度
CylinderGeometryCylinderOutlineGeometry圆柱、圆锥圆柱、圆锥或者截断的圆锥
EllipseGeometryEllipseOutlineGeometry椭圆椭圆或者拉伸的椭圆
EllipsoidGeometryEllipsoidOutlineGeometry椭球体椭球体
RectangleGeometryRectangleOutlineGeometry矩形矩形或者拉伸的矩形
PolygonGeometryPolygonOutlineGeometry多边形多边形,可以具有空洞或者拉伸一定的高度
PolylineGeometrySimplePolylineGeometry多段线多段线,可以具有一定的宽度
PolylineVolumeGeometryPolylineVolumeOutlineGeometry多段线柱体多段线柱体
SphereGeometrySphereOutlineGeometry球体球体
WallGeometryWallOutlineGeometry

Geometry Instances - 几何体实例

相当于 Geometry 的容器,而多个 Instance 可以公用一个 Geomotry 并利用 GeometryInstance.modelMatrix 提供多种属性信息。

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,提高我们的性能。

⚠️ 但是不同类别的几何图形不能放一起!如 Outline 为一类 geometryInstances,非轮廓的为另一类

// 填充面几何实例
var instances = [Instance1, Instance2, Instance3, ……];
scene.primitives.add(new Cesium.Primitive({
  geometryInstances: instances, //合并
  // 某些外观允许每个几何图形实例分别指定某个属性,例如:
  appearance: new Cesium.PerInstanceColorAppearance({translucent: false, closed: true})
}));

// 轮廓几何实例
var outlineInstances = [OutlineInstance1, OutlineInstance2, OutlineInstance3, ……];
scene.primitives.add(new Cesium.Primitive({
  geometryInstances: outlineInstances, //合并
  // 某些外观允许每个几何图形实例分别指定某个属性,例如:
  appearance: new Cesium.PerInstanceColorAppearance({translucent: false, closed: true})
}));
更新单个 Instance 属性

在添加到 Primitive 后,我们仍然可以通过 Id 获取指定 Instance 并修改其属性。

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 - 外观

⚠️ 注意:有些外观和几何是不兼容的。 例如 EllipsoidSurfaceAppearanceWallGeometry 就不能搭配,原因是后者是垂直于地表的。即使外观与几何图形兼容,它们还必须有匹配的顶点格式(vertex formats)—— 即几何图形必须具有外观可以作为输入的数据格式,在创建 Geometry 时可以提供 VertexFormat

Cesium 支持的 Appearance
外观描述
MaterialAppearance支持各种 Geometry 类型的外观,支持使用材质来定义着色。支持材料描述阴影。
EllipsoidSurfaceAppearanceMaterialAppearance 的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(vertex attributes)的计算。和 Material Appearance 一样,就像一个多边形,并且使用这个假设来通过程序上计算许多顶点属性来节省内存。
PerInstanceColorAppearance让每个实例使用自定义的颜色来着色,使用每个实例的颜色来遮蔽每个实例。
PolylineMaterialAppearance支持使用材质来着色多段线。支持材料遮蔽 Polyline。
PolylineColorAppearance使用每顶点或者每片段(per-vertex or per-segment )的颜色来着色多段线—使用每顶点或每段着色来遮蔽折线

Appearance 定义了需要在 GPU上 执行的 GLSL 着色器,这部分一般只有在自定义外观时需要修改。

render state 用来在绘制 Primitive 的时候控制 GPU 状态,一旦外观被创建,render state 就不能再改变了,但是我们可以修改其材质。

//下面的外观可用于定义一个 Viewer 可进入的透视盒子
var appearance = new Cesium.PerInstanceColorAppearance({
  translucent: true,
  closed: true
});

//下面的代码效果同上
var appearance1 = new Cesium.PerInstanceColorAppearance({
  renderState: {
    depthTest: {
      enabled: true
    },
    cull: {
      enabled: true,
      face: Cesium.CullFace.BACK
    }
  }
});

自定义着色器(示例:雷达动效

雷达动效

/** 1. 数据准备 */
// 雷达的高度
var length = 400000.0;
// 地面位置(垂直地面)
 var positionOnEllipsoid = Cesium.Cartesian3.fromDegrees(116.39, 39.9);
// 中心位置
var centerOnEllipsoid = Cesium.Cartesian3.fromDegrees(116.39, 39.9, length*0.5);
// 顶部位置(卫星位置)
var topOnEllipsoid = Cesium.Cartesian3.fromDegrees(116.39, 39.9,length);
// 矩阵计算
var modelMatrix = Cesium.Matrix4.multiplyByTranslation( // 转换矩阵
  Cesium.Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid), // 矩阵
  new Cesium.Cartesian3(0.0, 0.0, length * 0.5), // 要转换的笛卡尔坐标
  new Cesium.Matrix4() // 返回新的矩阵
 );

/** 2. Geometry: 创建一个圆锥几何图形 */
//1. 构造 geometry
var cylinderGeometry = new Cesium.CylinderGeometry({
  length: length,
  topRadius: 0.0,
  bottomRadius: length * 0.5,
  vertexFormat: Cesium.MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat
});
//2. 创建 GeometryInstance
var redCone = new Cesium.GeometryInstance({
  geometry: cylinderGeometry, //geomtry类型
  modelMatrix: modelMatrix, //模型矩阵 调整矩阵的位置和方向
});

**/** 3. shader着色器: 定义glsl代码 */**
const source =
//传入的动态数值
`uniform vec4 color;
 uniform float repeat;
 uniform float offset;
 uniform float thickness;

//设置图形外观材质
czm_material czm_getMaterial(czm_materialInput materialInput){
    czm_material material = czm_getDefaultMaterial(materialInput); //获取内置的默认材质
    float sp = 1.0/repeat; //重复贴图
    vec2 st = materialInput.st; //二维纹理坐标
    float dis = distance(st, vec2(0.5)); //计算距离
    float m = mod(dis + offset, sp); //间隔
    float a = step(sp*(1.0-thickness), m);//线条拼色
 //修改材质
    material.diffuse = color.rgb;
    material.alpha = a * color.a;
 return material;
}`

/** 4. appearance */
//1. 自定义material外观材质,修改着色器
const material = new Cesium.Material({
 fabric: {
  type: 'VtxfShader1',
  uniforms: { //动态传递参数
   color: new Cesium.Color(0.2, 1.0, 0.0, 1.0),
   repeat: 30.0,
   offset: 0.0,
   thickness: 0.3,
  },
  source :source
  },
  translucent: false
})
//2. 定义appearance外观
const appearance = new Cesium.MaterialAppearance({
 material:material, // 自定义的材质
 faceForward : false, // 当绘制的三角面片法向不能朝向视点时,自动翻转法向,从而避免法向计算后发黑等问题
 closed: true // 是否为封闭体,实际上执行的是是否进行背面裁剪
})

/** 5. 创建 Primitive */
//1. 添加 Primitive
var radar = viewer.scene.primitives.add(
  new Cesium.Primitive({
  geometryInstances: [redCone],
  appearance:appearance
 })
);
//2. 动态修改雷达材质中的 offset 变量,从而实现动态效果。
viewer.scene.preUpdate.addEventListener(function() {
 let { offset } = radar.appearance.material.uniforms;
  offset -= 0.001;
 if (offset > 1.0) {
  offset = 0.0;
 }
 radar.appearance.material.uniforms.offset = offset;
})

参考资料

Cesium | Primitive图元介绍及与Entity对比 - 掘金
Cesium | 海量点的加载与性能优化 - 掘金
Part I: Custom Geometry & Appearances – Cesium
Part II: Geometry and Appearances · CesiumGS/cesium Wiki
Cesium原理篇:Material - fu*k - 博客园
cesium| Primitive图元自定义着色器(1) | 一只咸鱼 | 努力学习最新姿势!!!

;