一、PointPrimitive 核心认知
1.1 什么是 PointPrimitive
PointPrimitive 是 Cesium 中用于渲染单个点状图形的基础类,表现为 3D 场景中一个可配置颜色、大小、轮廓的像素点,通常用于标记坐标点(如 GPS 定位、设备点位、兴趣点 POI 等)。
1.2 核心注意事项
- 禁止直接调用构造函数:
new Cesium.PointPrimitive()是错误用法,必须通过PointPrimitiveCollection#add()创建(类似 Label 依赖 LabelCollection); - 性能特性:单个属性读取为常量时间,赋值虽为常量时间但会触发 CPU 到 GPU 的数据传输(批量更新建议清空重建);
- 渲染逻辑:点的大小以像素为单位,不受场景缩放影响(除非配置
scaleByDistance),适合标记固定像素尺寸的点位。
1.3 适用场景
- 海量点位渲染(如数万级 GPS 轨迹点、城市 POI 点);
- 实时更新的设备点位(如物联网设备、移动终端定位);
- 简单的坐标标记(无需复杂模型/图标,仅需点状提示)。
二、基础使用:创建第一个 PointPrimitive
2.1 完整基础示例
以下是创建 PointPrimitiveCollection 并添加点元的最小可运行代码,覆盖核心步骤:
// 1. 初始化 Cesium Viewer
const viewer = new Cesium.Viewer("cesiumContainer", {
terrain: Cesium.Terrain.fromWorldTerrain(), // 可选:加载地形
animation: false,
timeline: false
});
// 2. 创建 PointPrimitiveCollection 集合(管理点元)
const pointCollection = new Cesium.PointPrimitiveCollection();
// 将集合添加到场景的原语中(关键:否则点元不会显示)
viewer.scene.primitives.add(pointCollection);
// 3. 添加单个 PointPrimitive 点元
const point = pointCollection.add({
// 点位坐标(示例:北京经纬度转笛卡尔坐标)
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 100),
// 核心配置
pixelSize: 10, // 点的内部像素大小
color: Cesium.Color.RED, // 点的填充色
outlineColor: Cesium.Color.WHITE, // 轮廓颜色
outlineWidth: 2, // 轮廓像素宽度
show: true, // 是否显示
id: "beijing-point" // 自定义 ID(拾取时返回)
});
// 4. 视角聚焦到点元位置
viewer.zoomTo(pointCollection);
2.2 核心步骤解析
- 创建集合:PointPrimitive 必须依赖
PointPrimitiveCollection管理,先创建集合并添加到场景; - 添加点元:通过
add()方法传入配置参数,返回 PointPrimitive 实例可后续修改属性; - 场景挂载:集合必须通过
scene.primitives.add()挂载到场景,否则点元无法渲染。
三、核心属性详解
3.1 基础属性(必配)
| 属性名 | 类型 | 默认值 | 作用 | 示例 |
|---|---|---|---|---|
position |
Cartesian3 |
- | 点元的 3D 笛卡尔坐标 | Cesium.Cartesian3.fromDegrees(116.4, 39.9, 100) |
pixelSize |
number |
- | 点的内部像素大小 | 10(10 像素直径) |
color |
Color |
- | 点的填充色(支持透明度) | Cesium.Color.RED / new Cesium.Color(1,0,0,0.5)(半透明红) |
show |
boolean |
true |
是否显示点元 | false(隐藏点元) |
id |
* |
undefined |
自定义标识(拾取时返回) | "point-1" / {id: 1, name: "北京"} |
示例:配置带透明度的点元
pointCollection.add({
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 100),
pixelSize: 15,
// 半透明蓝色(RGBA:0,0,1,0.6)
color: new Cesium.Color(0, 0, 1, 0.6),
show: true
});
3.2 轮廓配置属性
| 属性名 | 类型 | 默认值 | 作用 | 注意事项 |
|---|---|---|---|---|
outlineColor |
Color |
- | 点的轮廓颜色 | 需配合 outlineWidth 使用 |
outlineWidth |
number |
- | 轮廓像素宽度 | 宽度会叠加到 pixelSize 上,总大小 = 内部尺寸 + 2*轮廓宽度 |
示例:带白色轮廓的红色点元
pointCollection.add({
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 100),
pixelSize: 8, // 内部8像素
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE, // 白色轮廓
outlineWidth: 2, // 轮廓2像素 → 总大小 12 像素
show: true
});
3.3 距离相关动态属性
这类属性基于相机与点元的距离动态调整点的大小/透明度,核心依赖 NearFarScalar 类(需保证 far > near,否则抛出 DeveloperError)。
1. scaleByDistance:距离缩放
- 作用:根据相机距离动态调整点的缩放比例(缩放
pixelSize和outlineWidth); - 参数:
NearFarScalar(near, nearValue, far, farValue)(near/far 为距离,nearValue/farValue 为对应缩放比例)。
示例:距离越远,点越小(直至消失)
point.scaleByDistance = new Cesium.NearFarScalar(
1000, // 相机距离点 1000 米内
2.0, // 缩放比例 2 倍(点变大)
8000, // 相机距离点 8000 米外
0.0 // 缩放比例 0(点消失)
);
2. translucencyByDistance:距离透明度
- 作用:根据相机距离动态调整点的透明度;
- 参数:
NearFarScalar(near, nearValue, far, farValue)(透明度值 0-1,1 为不透明,0 为完全透明)。
示例:距离越远,点越透明
point.translucencyByDistance = new Cesium.NearFarScalar(
1000, // 1000 米内
1.0, // 完全不透明
8000, // 8000 米外
0.0 // 完全透明
);
3. distanceDisplayCondition:距离显示条件
- 作用:限定点元仅在指定距离范围内显示;
- 参数:
DistanceDisplayCondition(near, far)(near 为最小显示距离,far 为最大显示距离)。
示例:仅在 500-5000 米范围内显示
point.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(500, 5000);
3.4 高级属性
1. disableDepthTestDistance:禁用深度测试距离
- 作用:设置距离相机多少米内禁用深度测试,避免点元被地形/模型遮挡;
- 取值:
0:始终启用深度测试(默认);Number.POSITIVE_INFINITY:始终禁用深度测试(点元永远在最上层);- 具体数值(如 10000):10000 米内禁用深度测试。
示例:避免点元被地形遮挡
point.disableDepthTestDistance = Number.POSITIVE_INFINITY; // 始终在最上层
2. splitDirection:分割方向
- 作用:用于多视图分割场景(如左右屏、上下屏),指定点元在哪个分割视图中显示;
- 默认值:
Cesium.SplitDirection.NONE(所有视图显示); - 常用值:
SplitDirection.LEFT(仅左视图)、SplitDirection.RIGHT(仅右视图)。
示例:仅左视图显示点元
point.splitDirection = Cesium.SplitDirection.LEFT;
四、核心方法详解
4.1 computeScreenSpacePosition(scene, result)
- 作用:计算点元在屏幕空间的坐标(画布左上角为原点,x 向右、y 向下);
- 参数:
scene:场景实例(viewer.scene);result(可选):存储结果的 Cartesian2 对象(避免重复创建);
- 返回值:
Cartesian2屏幕坐标。
示例:获取点元的屏幕坐标
const screenPos = point.computeScreenSpacePosition(viewer.scene);
console.log("点元屏幕坐标:", screenPos.x, screenPos.y);
4.2 equals(other)
- 作用:判断两个点元是否相等(所有属性完全一致则返回 true);
- 参数:待比较的 PointPrimitive 实例;
- 返回值:
boolean。
示例:比较两个点元
const point1 = pointCollection.add({...});
const point2 = pointCollection.add({...});
console.log("点元是否相等:", point1.equals(point2)); // false
五、批量操作与性能优化
5.1 批量添加点元(高性能)
当需要添加大量点元(如数万级),建议批量循环添加后统一渲染:
// 批量添加 1000 个随机点元
function addBatchPoints(count) {
// 暂停渲染(减少中间渲染开销)
viewer.scene.requestRenderMode = true;
for (let i = 0; i < count; i++) {
// 随机经纬度(北京周边)
const lon = 116.0 + Math.random() * 1.0;
const lat = 39.8 + Math.random() * 0.4;
// 随机颜色
const color = Cesium.Color.fromRandom({ alpha: 0.8 });
pointCollection.add({
position: Cesium.Cartesian3.fromDegrees(lon, lat, 50),
pixelSize: 8,
color: color,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 1
});
}
// 手动触发渲染
viewer.scene.requestRender();
viewer.scene.requestRenderMode = false;
}
// 调用:添加 1000 个点元
addBatchPoints(1000);
5.2 批量更新:清空重建优于逐个修改
根据 Cesium 官方建议,若大部分点元需要更新属性,清空集合后重新添加比逐个修改更高效:
// 低效方式:逐个修改(不推荐)
for (let i = 0; i < pointCollection.length; i++) {
const p = pointCollection.get(i);
p.color = Cesium.Color.BLUE; // 每个修改都触发 GPU 传输
}
// 高效方式:清空重建(推荐)
pointCollection.removeAll(); // 清空旧点元
// 重新添加更新后的点元
addBatchPoints(1000); // 批量添加新配置的点元
5.3 临时隐藏:用 show 替代增删
临时隐藏点元时,优先设置 show: false,而非移除后重新添加:
// 低效方式(不推荐)
pointCollection.remove(point); // 移除
// ... 后续重新添加
pointCollection.add({...});
// 高效方式(推荐)
point.show = false; // 隐藏
// ... 后续显示
point.show = true;
5.4 避免重复创建集合
多次更新点元时,复用同一个 PointPrimitiveCollection 比反复创建新集合更高效:
// 错误方式(性能差)
function updatePointsBad() {
// 每次更新都创建新集合
const newCollection = new Cesium.PointPrimitiveCollection();
viewer.scene.primitives.remove(pointCollection); // 移除旧集合
viewer.scene.primitives.add(newCollection); // 添加新集合
// ... 添加点元
}
// 正确方式(性能优)
function updatePointsGood() {
// 复用现有集合,清空后重建
pointCollection.removeAll();
addBatchPoints(1000); // 重新添加点元
}
六、交互实现:点元拾取与点击事件
6.1 点元拾取(获取点击的点元)
通过 scene.pick() 方法可拾取鼠标点击位置的点元,结合 id 属性实现交互:
// 监听鼠标左键点击事件
viewer.screenSpaceEventHandler.setInputAction((event) => {
// 获取点击位置的原语
const pickedObject = viewer.scene.pick(event.position);
// 判断是否拾取到 PointPrimitive
if (Cesium.defined(pickedObject) && pickedObject.id) {
alert(`你点击了点元:${pickedObject.id}`);
// 示例:修改点击点元的颜色
pickedObject.color = Cesium.Color.GREEN;
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
6.2 点元高亮(鼠标悬浮效果)
结合鼠标移动事件实现点元悬浮高亮:
let highlightedPoint = null; // 记录当前高亮的点元
// 监听鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction((event) => {
// 清除上一个高亮点元的样式
if (Cesium.defined(highlightedPoint)) {
highlightedPoint.pixelSize = 8; // 恢复原大小
highlightedPoint.outlineWidth = 1; // 恢复原轮廓
highlightedPoint = null;
}
// 拾取当前鼠标位置的点元
const pickedObject = viewer.scene.pick(event.endPosition);
if (Cesium.defined(pickedObject) && pickedObject instanceof Cesium.PointPrimitive) {
// 高亮样式:放大尺寸 + 加粗轮廓
highlightedPoint = pickedObject;
highlightedPoint.pixelSize = 12;
highlightedPoint.outlineWidth = 3;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
七、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 点元不显示 | 1. 集合未添加到 scene.primitives;2. 坐标错误;3. show: false |
1. 调用 viewer.scene.primitives.add(pointCollection);2. 检查坐标格式;3. 确认 show: true |
| 点元被地形/模型遮挡 | 深度测试导致 | 设置 disableDepthTestDistance: Number.POSITIVE_INFINITY |
抛出 scaleByDistance.far must be greater than scaleByDistance.near |
NearFarScalar 的 far ≤ near |
确保 far 值大于 near 值(如 new NearFarScalar(1000, 2, 8000, 0)) |
| 批量更新性能差 | 逐个修改点元属性 | 清空集合(removeAll())后重新添加点元 |
| 点元大小随场景缩放变化 | 误配置 scaleByDistance 或像素尺寸过大 |
1. 移除 scaleByDistance;2. 调整 pixelSize 为合理值(1-20) |
八、PointPrimitive vs Billboard 对比
很多开发者会混淆 PointPrimitive 和 Billboard(广告牌),两者核心区别如下:
| 特性 | PointPrimitive | Billboard |
|---|---|---|
| 表现形式 | 像素点(无纹理) | 图片/画布纹理(可加载图标) |
| 大小单位 | 像素(固定尺寸) | 像素(固定尺寸) |
| 性能 | 极高(海量点位首选) | 较高(需加载纹理,略逊于点元) |
| 样式配置 | 仅颜色、大小、轮廓 | 支持图片、旋转、拉伸等 |
| 适用场景 | 海量简单点位标记 | 需自定义图标/图片的点位 |
总结
- PointPrimitive 是 Cesium 中渲染高性能点状图形的核心类,禁止直接调用构造函数,必须通过
PointPrimitiveCollection#add()创建; - 核心配置包括:位置(position)、大小(pixelSize)、颜色(color)、轮廓(outlineColor/outlineWidth),以及距离相关的动态属性(scaleByDistance/translucencyByDistance);
- 性能优化关键:批量更新优先清空重建、临时隐藏用
show属性、复用集合避免重复创建、禁用深度测试解决遮挡问题。
书签篮