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
ModelGraphics gltf 3d 模型
Cesium3DTilesetGraphics 3d 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
几何图形 轮廓几何图形 类别 说明
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 提供多种属性信息。

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 类型的外观,支持使用材质来定义着色。支持材料描述阴影。
EllipsoidSurfaceAppearance MaterialAppearance 的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(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
    }
  }
});

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

Cesium: Primitive vs Entity_第1张图片

/** 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) | 一只咸鱼 | 努力学习最新姿势!!!

你可能感兴趣的:(cesium,前端,javascript,几何学)