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,
},
});
实体类型 | 说明 |
---|---|
BillboardGraphics | 点,广告牌,图片标注 |
LabelGraphics | 点,文字标注 |
PointGraphics | 点,或者填充颜色的圆 |
CorridorGraphics | 走廊:沿着地表的多段线(垂直于表面的折线),且具有一定的宽度,可以拉伸到一定的高度 |
CylinderGraphics | 圆柱、圆锥或者截断的圆锥 |
EllipseGraphics | 椭圆或者拉伸的椭圆 |
EllipsoidGraphics | 椭球体 |
RectangleGraphics | 矩形或者正柱体 |
PlaneGraphics | 平面 |
PolygonGraphics | 多边形,可以具有空洞或者拉伸一定的高度 |
PathGraphics | 多段线,以路径方式呈现,可随时间移动 |
PolylineGraphics | 多段线,可以具有一定的宽度 |
PolylineVolumeGraphics | 多段线柱体 |
BoxGraphics | 立方体 |
WallGraphics | 墙 |
ModelGraphics | gltf 3d 模型 |
Cesium3DTilesetGraphics | 3d tiles tileset |
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 或主线程上创建和批处理。
其具有以下优势:
Geometry
,减轻 CPU 负担,更好使用 GPU。Geometry
和 Appearance
解耦,两者可独立修改。同样的,使用 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')
})
}));
⚠️ 为方便使用,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,
});
}
图形集合 | 说明 |
---|---|
BillboardCollection | 图标。为了获得最佳性能,最好选择几个系列,每个系列都有许多图形,而不是许多系列,每个系列只有零星的图形。组织图形,使具有相同更新频率的图形位于同一集合中,如不更改的图形应位于一个集合中,每一帧都变化的图形应该在另一个集合中。 |
LabelCollection | 文字。为了获得最佳性能,参考 BillboardCollection |
PointPrimitiveCollection | 点。为了获得最佳性能,参考 BillboardCollection |
PolylineCollection | 多段线。为了获得最佳性能,参考 BillboardCollection |
CloudCollection | 云特效 |
几何图形 | 轮廓几何图形 | 类别 | 说明 |
---|---|---|---|
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 的容器,而多个 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'
});
我们可以合并多个 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})
}));
在添加到 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
}));
⚠️ 注意:有些外观和几何是不兼容的。 例如 EllipsoidSurfaceAppearance
与 WallGeometry
就不能搭配,原因是后者是垂直于地表的。即使外观与几何图形兼容,它们还必须有匹配的顶点格式(vertex formats)—— 即几何图形必须具有外观可以作为输入的数据格式,在创建 Geometry
时可以提供 VertexFormat
。
外观 | 描述 |
---|---|
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
}
}
});
/** 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) | 一只咸鱼 | 努力学习最新姿势!!!