🚀 个人简介:某大型测绘遥感企业资深Webgis开发工程师,软件设计师(中级)、优快云优质创作者
💟 作 者:柳晓黑胡椒❣️
📝 专 栏:再识Cesium
🌈 若有帮助,还请关注 ➕ 点赞➕收藏,不行的话我再努努力💪💪💪
本文基于 Cesium 1.132 版本进行演示,其他版本在 API 上可能略有不同。
本文整理了常见的primtive应用,配合示例代码,你可以在实际项目中直接使用或二次封装,提升开发效率。
✨ 欢迎大家在评论区提出建议或交流心得,如果需要完整源码,可以私聊我获取。
Primitive 是什么

一、Primitive 是什么
在 Cesium 中,Primitive 是最底层的渲染单元,它直接和 WebGL 渲染管线 打交道。
如果把 Cesium 比作一栋大楼:
- Entity 就像是“装修后的房子”,拿来即用,方便开发。
- Primitive 就像是“钢筋混凝土结构”,更接近底层,可以自由搭建,但需要更多代码。
1. 官方定义
Primitive 是 由几何(Geometry)+ 外观(Appearance)组合而成的渲染对象。
- Geometry 决定了形状(比如盒子、球体、多边形)。
- Appearance 决定了外观(颜色、纹理、材质、光照)。
两者结合,就能把一个抽象的几何体真正绘制到地球场景中。
2. 为什么需要 Primitive?
Cesium 最早就是围绕 Primitive 构建的,Entity 其实只是对 Primitive 的封装。
- Entity = 上层封装,快速开发
- Primitive = 底层实现,性能优先
换句话说,所有 Entity 最终都会被拆解为一个或多个 Primitive 才能渲染。
当你的数据量很小,用 Entity 就够了;但当需要渲染 几十万甚至上百万个对象 时,Primitive 能显著提升性能。
3. Primitive 的生命周期
一个 Primitive 在 Cesium 中的典型流程:
- 构造 Geometry(定义形状、顶点、索引)。
- 指定 Appearance(定义着色方式、纹理、材质)。
- 交给 Primitive 对象,加入
scene.primitives中。 - Cesium 会在渲染循环中把它转换成 WebGL 缓冲区和着色器,最终绘制到画布上。
4. 与 Entity 的关系
可以把 Entity 看成是对 Primitive 的 一层语法糖:
- Entity:封装了属性(position、material、orientation…),让开发者更容易上手。
- Primitive:直接操作几何和渲染参数,更灵活,但写法更复杂。
Primitive 的优点 & 与 Entity 的区别
👉 Entity = 开发效率优先,Primitive = 性能与灵活性优先。
1. Primitive 的优点
Primitive 的核心优势在于 性能与灵活性:
-
高性能渲染
- Entity 是对 Primitive 的封装,Cesium 会帮你自动维护各种属性(位置、材质、时间动态等)。
- 当数据量很大(比如几十万点),Entity 管理开销非常大,而 Primitive 更接近底层,直接走 WebGL 管线,性能更高。
-
批量绘制(Batching)
- Primitive 支持 Instance,可以把多个几何对象合并为一个 Primitive 提交给 GPU,大大减少绘制开销。
- 例如渲染 10 万个点时,Entity 会创建 10 万个对象,而 Primitive 可以一次性传给 GPU。
-
灵活的渲染控制
- 可以直接自定义 Geometry(顶点、索引、法线)和 Appearance(着色器)。
- 支持更复杂的效果,比如自定义 GLSL Shader,光照算法,甚至实现特殊材质。
-
底层可扩展性
- Primitive 是 Cesium 的基础设施,所有高层功能(Entity、DataSource)最终都会转成 Primitive 来渲染。
- 如果你需要突破 Entity 的限制,就必须使用 Primitive。
2. Entity 与 Primitive 的区别
| 对比维度 | Entity | Primitive |
|---|---|---|
| 定位 | 高层封装,业务友好 | 底层渲染,高性能优化 |
| 开发难度 | 简单,几行代码即可 | 较复杂,需要理解 Geometry & Appearance |
| 性能 | 小规模数据表现好 | 大规模数据优势明显 |
| 动态属性 | 内置支持时间动态(SampledProperty 等) | 需手动实现 |
| 渲染控制 | 封装完善,可快速调用 | 灵活度高,可自定义 Shader |
| 适用场景 | 中小规模应用,快速原型开发 | 海量数据、特殊可视化、性能优化 |
3. 如何选择?
-
优先使用 Entity:
如果你的项目是业务导向、数据量不大(几千以内)、追求开发效率。 -
使用 Primitive:
如果你的项目需要渲染 大规模数据(>10万),或者要做 特殊渲染效果(自定义着色、特殊几何)。
Primitive 构成
在 Cesium 的渲染体系中,一个 Primitive = Geometry + Appearance。
- Geometry(几何):决定物体的形状、空间位置和顶点信息(物体“长成什么形状”)。
- Appearance(外观):决定物体的材质、颜色、纹理和着色方式(物体“看起来怎么样”)。

Geometry
- 负责描述物体的结构和顶点数据。
- 常见内置几何:BoxGeometry、PolygonGeometry、SphereGeometry 等。
- 一个 Geometry 包含:
- 顶点(Vertices):几何形状的空间坐标点。
- 索引(Indices):定义顶点之间的连接关系。
- 法线(Normals):用于光照计算。
- 纹理坐标(UV):控制贴图如何映射到表面。
👉 举例:BoxGeometry 会生成一个立方体的顶点和索引;PolygonGeometry 会生成多边形的边和面。

Appearance
- 负责描述几何体“长什么样子”。
- 内置的 Appearance 有:
- MaterialAppearance:使用材质系统(支持颜色、图片纹理、渐变、光照)。
- PerInstanceColorAppearance:为每个实例单独指定颜色,性能较高。
- EllipsoidSurfaceAppearance:适用于地表贴图。
- PolylineMaterialAppearance:用于线,支持虚线、箭头等。
👉 Appearance 的本质是 一个着色器(Shader),你甚至可以自己写 GLSL Shader 来实现特殊效果(比如发光、扫描、流动)。

Primitive 应用
1.添加单个实例
👉 示例说明:添加一个蓝色的圆形 Primitive
const primitiveCollection = new Cesium.PrimitiveCollection()
const circle = new Cesium.CircleGeometry({center: Cesium.Cartesian3.fromDegrees(114.347137, 30.541429, 100), radius: 200.0});
const geometry = Cesium.CircleGeometry.createGeometry(circle);
const instance = new Cesium.GeometryInstance({geometry: geometry,});
primitiveCollection.add(new Cesium.Primitive({
geometryInstances: instance,
asynchronous: false, // 关闭异步
appearance: new Cesium.MaterialAppearance({
material: new Cesium.Material({
fabric: {
type: "Color",
uniforms: {color: Cesium.Color.BLUE}
}
})
})
}));
const boundingSphere = geometry.boundingSphere; // 获取几何体的包围球
viewer.camera.flyToBoundingSphere(boundingSphere);

2.添加多几何不同外观实例
👉 示例说明:批量添加 10 万个立方体,每个实例都有不同颜色
const primitiveCollection = new Cesium.PrimitiveCollection()
const instances = [];
const positions = []; // 记录用于计算 boundingSphere
let boxGeometry = Cesium.BoxGeometry.fromDimensions({dimensions: new Cesium.Cartesian3(100, 100, 100)})
for (let i = 0; i < 100000; i++) {
const position = Cesium.Cartesian3.fromDegrees(114.347137 + Math.random(), 30.541429 + Math.random(), 200 + Math.random() * 100)
const instance = new Cesium.GeometryInstance({
geometry: boxGeometry,
modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(position),//通过modelMatrix设置不同的位置
id: "BoxGeometry" + i,
// 每个实例几何颜色得值和类型信息
attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({alpha: 1}))}
});
instances.push(instance);
positions.push(position)
}
primitiveCollection.add(new Cesium.Primitive({
geometryInstances: instances,
// appearance: new Cesium.EllipsoidSurfaceAppearance({material: Cesium.Material.fromType('Color')}),
appearance: new Cesium.PerInstanceColorAppearance({flat: true, translucent: false})// 具有颜色属性得geometryInstance实例的外观
}));
// 计算一个包含笛卡尔点坐标得紧合边界球
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
viewer.camera.flyToBoundingSphere(boundingSphere);

3.添加大量点
👉 示例说明:批量绘制全球范围内的点位,每个点有随机颜色和图标
const billboardsCollection = new Cesium.BillboardCollection()
const color = () => new Cesium.Color(Math.random(), Math.random(), Math.random(), 1); // 随机颜色
for (let longitude = -180; longitude < 180; longitude++) {
for (let latitude = -90; latitude < 90; latitude++) {
billboardsCollection.add({
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
image: png5, // 图标
scale: 0.5, // 调整图标的大小
color: color(), // 随机颜色
id: 'billboard' + '-' + longitude + '-' + latitude
})
}
}

4.添加大量线面
👉 示例说明:全球范围内绘制上万条线和多边形面,使用不同颜色区分。
const instances1 = [];
const instances2 = [];
for (let i = 0; i < 10000; i++) {
const longitude = Math.random() * 360 - 180;
const latitude = Math.random() * 180 - 90;
const positions = [longitude, latitude, longitude + Math.random(), latitude, longitude, latitude + Math.random()];
const lineInstance = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: Cesium.Cartesian3.fromDegreesArray(positions),
width: 3,
vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
}),
attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(i % 2 == 0 ? 'green' : 'red').withAlpha(1))},
id: 'line' + i
});
const faceInstance = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(positions)),
height: 0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(i % 2 == 0 ? 'red' : 'green').withAlpha(1))},
id: 'face' + i
})
instances1.push(lineInstance);
instances2.push(faceInstance);
}
primitiveCollection.add(new Cesium.Primitive({
geometryInstances: instances1,
appearance: new Cesium.PolylineColorAppearance()
}));
primitiveCollection.add(new Cesium.Primitive({
geometryInstances: instances2,
appearance: new Cesium.PerInstanceColorAppearance({closed: true})
}));

5.添加大量曲线
👉 示例说明:全球范围内批量绘制上百条随机曲线,每条曲线带有不同的颜色。
const instances = [];
const getColor = () => '#' + Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, '0')
for (let i = 0; i < 300; i++) {
const positions = Array.from({length: 10}, () => Math.random() * 360 - 180).reduce((acc, cur) => acc.concat(cur), [])
const instance = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: generateCurvePoints(positions, 20),
width: 2,
vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
}),
attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(getColor()).withAlpha(0.6))},
id: "curve" + i
})
instances.push(instance)
}
primitiveCollection.add(new Cesium.Primitive({
geometryInstances: instances,
appearance: new Cesium.PolylineColorAppearance()
}));

6.添加大量立方体
👉 示例说明:全球范围内绘制上万个半透明的立方体
const instances = [];
for (let i = 0; i < 10000; i++) {
const longitude = Math.random() * 360 - 180;
const latitude = Math.random() * 180 - 90;
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0);
const dimensions = new Cesium.Cartesian3(40000.0, 30000.0, 500000.0);
const color = Cesium.Color.RED.withAlpha(0.2);
instances.push(new Cesium.GeometryInstance({
geometry: new Cesium.BoxGeometry.fromDimensions({
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
dimensions: dimensions
}),
modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(position),
attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)}
}));
}
primitiveCollection.add(new Cesium.Primitive({
geometryInstances: instances,
appearance: new Cesium.PerInstanceColorAppearance()
}));

Takeaways
在这一篇中,我们系统介绍了 Primitive 的概念、优势、基本构成以及常见使用示例。通过这些例子,你应该已经能感受到 Primitive 相较于 Entity 在性能和灵活性上的差异,也对 Geometry 与 Appearance 的组合有了更直观的理解。
不过,Primitive 的强大远不止于此。下一节我们将深入 Primitive 的几何类型 Geometry,并进一步探讨 如何使用自定义顶点来构建底层 Primitive。这一部分会更贴近图形学的底层逻辑,例如顶点、索引、法线等内容,非常适合对 Cesium 内部渲染机制感兴趣的同学
Cesium Primitive 全面解析
112

被折叠的 条评论
为什么被折叠?



