一、LabelCollection 核心认知
1.1 什么是 LabelCollection
LabelCollection 是 Cesium 中用于批量管理多个 Label(标签) 的渲染集合类,它将多个标签打包成一个渲染原语(Primitive)提交给 GPU,相比逐个创建 Entity 标签,能大幅减少渲染状态切换和 GPU 调用开销,是处理大量标签(数十/数百/数千个) 的最优选择。
1.2 核心定位:何时用 LabelCollection 而非 Entity
| 使用场景 | 推荐方案 | 核心原因 |
|---|---|---|
| 少量标签(< 50 个)、快速开发 | viewer.entities.add({label: {...}}) |
封装友好、API 简洁,无需手动管理生命周期 |
| 大量标签(≥ 50 个)、追求性能 | LabelCollection |
批量渲染、减少 GPU 开销,性能提升 2-10 倍 |
| 标签需分组管理(如静态/动态分离) | LabelCollection |
可按更新频率拆分多个 Collection,优化渲染效率 |
| 需自定义模型矩阵(局部坐标系) | LabelCollection |
原生支持 modelMatrix,Entity 需额外处理 |
1.3 核心特性
- 批量渲染:所有标签共享一个渲染上下文,减少 WebGL 状态切换;
- 统一配置:支持对整个集合设置
show、modelMatrix、blendOption等全局属性; - 高效增删:虽然增删标签会触发缓冲区重写,但整体效率远高于多个独立 Entity;
- 调试支持:内置
debugShowBoundingVolume调试边界球,便于定位渲染问题。
二、基础使用:创建第一个 LabelCollection
2.1 完整基础示例
以下是创建 LabelCollection 并添加标签的最小可运行代码,包含核心步骤:
// 1. 初始化 Cesium Viewer
const viewer = new Cesium.Viewer("cesiumContainer", {
terrain: Cesium.Terrain.fromWorldTerrain(), // 可选:加载地形
animation: false,
timeline: false
});
// 2. 创建 LabelCollection 实例(可传入全局配置)
const labelCollection = new Cesium.LabelCollection({
show: true, // 全局控制所有标签是否显示
blendOption: Cesium.BlendOption.OPAQUE_AND_TRANSLUCENT, // 混合模式(默认)
scene: viewer.scene, // 必须传入:如果标签使用 heightReference 或深度测试
modelMatrix: Cesium.Matrix4.IDENTITY // 模型矩阵(默认世界坐标系)
});
// 3. 将 Collection 添加到场景的原语集合中(关键步骤!)
viewer.scene.primitives.add(labelCollection);
// 4. 批量添加标签
// 示例1:添加基础标签(北京)
const label1 = labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 100),
text: "北京市中心",
font: "24px 微软雅黑",
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
});
// 示例2:添加带背景的标签(上海)
const label2 = labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(121.473701, 31.230416, 100),
text: "上海市中心",
font: "24px 微软雅黑",
fillColor: Cesium.Color.WHITE,
showBackground: true,
backgroundColor: new Cesium.Color(0, 0, 0, 0.5),
backgroundPadding: new Cesium.Cartesian2(10, 5)
});
// 5. 视角聚焦到标签区域
viewer.zoomTo(labelCollection);
2.2 核心步骤解析
- 创建 Collection:
new Cesium.LabelCollection(options)需传入scene(若使用高度参考/深度测试); - 添加到场景:必须通过
scene.primitives.add()将 Collection 加入场景,否则标签不会显示; - 添加标签:通过
add()方法添加单个标签,返回 Label 实例可后续修改; - 生命周期管理:可通过
remove()/removeAll()移除标签,destroy()销毁整个 Collection。
三、核心 API 详解
3.1 构造函数参数(options)
| 参数名 | 类型 | 默认值 | 作用 | 关键说明 |
|---|---|---|---|---|
modelMatrix |
Matrix4 |
Matrix4.IDENTITY |
模型到世界坐标系的变换矩阵 | 用于切换局部坐标系(如东-北-上坐标系) |
debugShowBoundingVolume |
boolean |
false |
调试边界球 | 仅调试用,显示每个渲染命令的边界球 |
scene |
Scene |
- | 场景实例 | 必传:若标签使用 heightReference 或深度测试 |
blendOption |
BlendOption |
OPAQUE_AND_TRANSLUCENT |
混合模式 | 优化性能:全不透明设 OPAQUE,全透明设 TRANSLUCENT,可提升 2 倍性能 |
show |
boolean |
true |
全局显示控制 | 一键隐藏/显示整个 Collection 的所有标签 |
关键示例:自定义模型矩阵(局部坐标系)
// 以北京为中心创建东-北-上局部坐标系
const center = Cesium.Cartesian3.fromDegrees(116.403874, 39.914885);
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
// 创建基于局部坐标系的 LabelCollection
const localLabelCollection = new Cesium.LabelCollection({
scene: viewer.scene,
modelMatrix: modelMatrix
});
viewer.scene.primitives.add(localLabelCollection);
// 标签位置基于局部坐标系(东/北/上方向)
localLabelCollection.add({
position: new Cesium.Cartesian3(0, 0, 0), // 中心点(北京)
text: "中心"
});
localLabelCollection.add({
position: new Cesium.Cartesian3(10000, 0, 0), // 东方向 10 公里
text: "东 10km"
});
localLabelCollection.add({
position: new Cesium.Cartesian3(0, 10000, 0), // 北方向 10 公里
text: "北 10km"
});
3.2 核心属性
| 属性名 | 类型 | 作用 | 示例 |
|---|---|---|---|
blendOption |
BlendOption |
修改混合模式 | labelCollection.blendOption = Cesium.BlendOption.OPAQUE; |
debugShowBoundingVolume |
boolean |
开启/关闭调试边界球 | labelCollection.debugShowBoundingVolume = true; |
length(只读) |
number |
获取标签数量 | for (let i=0; i<labelCollection.length; i++) {...} |
modelMatrix |
Matrix4 |
修改模型矩阵 | 见 3.1 局部坐标系示例 |
show |
boolean |
全局显示控制 | labelCollection.show = false; // 隐藏所有标签 |
3.3 核心方法
1. add(options) → Label
- 作用:添加单个标签到集合,返回 Label 实例(可后续修改属性);
- 性能:单次调用为常量时间,但会触发缓冲区重写(批量添加后统一渲染更高效);
- 示例:
const label = labelCollection.add({ position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 100), text: "自定义标签", font: "20px 微软雅黑", fillColor: Cesium.Color.RED }); // 后续修改标签属性 label.text = "修改后的文本"; label.scale = 1.5;
2. remove(label) → boolean
- 作用:从集合中移除指定标签,移除后标签不可再使用;
- 性能:单次调用为常量时间,但会触发缓冲区重写;
- 最佳实践:临时隐藏标签优先用
label.show = false,而非移除再添加; - 示例:
const label = labelCollection.add({...}); const isRemoved = labelCollection.remove(label); // 返回 true
3. removeAll()
- 作用:清空集合中所有标签;
- 性能:O(n) 复杂度,但比创建新 Collection 更高效;
- 示例:
labelCollection.removeAll(); // 清空所有标签
4. get(index) → Label
- 作用:根据索引获取标签,用于遍历所有标签;
- 性能:常量时间(若未渲染则隐式触发 O(n) 操作);
- 示例:
// 遍历所有标签,修改显示状态 const len = labelCollection.length; for (let i = 0; i < len; i++) { const label = labelCollection.get(i); label.show = !label.show; // 切换显示/隐藏 }
5. contains(label) → boolean
- 作用:检查集合是否包含指定标签;
- 示例:
const label = labelCollection.add({...}); const hasLabel = labelCollection.contains(label); // 返回 true
6. destroy() / isDestroyed()
- 作用:销毁 Collection 释放 WebGL 资源(关键:避免内存泄漏);
- 示例:
// 安全销毁:先检查是否已销毁 if (!labelCollection.isDestroyed()) { labelCollection = labelCollection && labelCollection.destroy(); }
四、高级特性与最佳实践
4.1 按更新频率拆分 Collection
Cesium 官方推荐:将静态标签和动态标签拆分到不同 Collection,避免动态更新影响静态标签的渲染性能。
// 1. 静态标签集合(仅初始化时添加,不更新)
const staticLabels = new Cesium.LabelCollection({
scene: viewer.scene,
blendOption: Cesium.BlendOption.OPAQUE // 全不透明,性能最优
});
viewer.scene.primitives.add(staticLabels);
// 添加静态标签(如城市名称)
staticLabels.add({...}); // 北京、上海、广州等
// 2. 动态标签集合(实时更新,如设备状态)
const dynamicLabels = new Cesium.LabelCollection({
scene: viewer.scene,
blendOption: Cesium.BlendOption.TRANSLUCENT // 含透明效果
});
viewer.scene.primitives.add(dynamicLabels);
// 模拟动态更新
setInterval(() => {
const len = dynamicLabels.length;
for (let i = 0; i < len; i++) {
const label = dynamicLabels.get(i);
label.text = `设备${i}: ${Math.random().toFixed(2)}`; // 实时更新文本
}
}, 1000);
4.2 混合模式优化(blendOption)
blendOption 是提升性能的关键参数,根据标签的透明度特性选择:
| 混合模式 | 适用场景 | 性能提升 |
|---|---|---|
BlendOption.OPAQUE |
所有标签无透明(alpha=1) | ~2 倍 |
BlendOption.TRANSLUCENT |
所有标签含透明(alpha<1) | ~2 倍 |
BlendOption.OPAQUE_AND_TRANSLUCENT |
混合透明/不透明标签 | 无提升(默认) |
示例:
// 全不透明标签集合(性能最优)
const opaqueLabels = new Cesium.LabelCollection({
scene: viewer.scene,
blendOption: Cesium.BlendOption.OPAQUE
});
4.3 避免频繁增删:优先使用 show 属性
临时隐藏标签时,不要调用 remove() + add(),而是直接修改 label.show:
// 低效方式(不推荐)
labelCollection.remove(label); // 移除
// ... 后续重新添加
labelCollection.add({...});
// 高效方式(推荐)
label.show = false; // 隐藏
// ... 后续显示
label.show = true;
4.4 批量增删后统一渲染
若需添加/移除大量标签,批量操作后再让 Cesium 渲染,避免多次触发缓冲区重写:
// 批量添加 1000 个标签(高效)
function addBatchLabels(count) {
// 先暂停渲染(可选,进一步优化)
viewer.scene.requestRenderMode = true;
for (let i = 0; i < count; i++) {
// 随机经纬度
const lon = 110 + Math.random() * 10;
const lat = 30 + Math.random() * 10;
labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(lon, lat, 100),
text: `标签${i}`,
font: "16px 微软雅黑",
fillColor: Cesium.Color.WHITE
});
}
// 手动触发渲染
viewer.scene.requestRender();
viewer.scene.requestRenderMode = false;
}
// 调用:批量添加 1000 个标签
addBatchLabels(1000);
4.5 结合 HeightReference 实现贴地/相对高度
LabelCollection 支持标签的高度参考,需确保构造函数传入 scene 参数:
labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 50),
text: "贴地标签",
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 贴地
});
labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 50),
text: "相对地面 50 米",
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND
});
五、性能对比:LabelCollection vs Entity
| 指标 | LabelCollection | Entity (label) | 优势方 |
|---|---|---|---|
| 渲染性能(1000 个标签) | 高(批量渲染) | 低(逐个渲染) | LabelCollection |
| API 简洁度 | 稍复杂(需手动管理) | 简单(自动封装) | Entity |
| 内存占用 | 低(共享缓冲区) | 高(独立对象) | LabelCollection |
| 动态更新效率 | 高(批量遍历) | 低(遍历 EntityCollection) | LabelCollection |
| 局部坐标系支持 | 原生支持(modelMatrix) | 需额外处理 | LabelCollection |
六、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 标签不显示 | 未将 Collection 添加到 scene.primitives |
调用 viewer.scene.primitives.add(labelCollection) |
| 深度测试异常(标签被地形遮挡) | 构造函数未传入 scene 参数 |
new LabelCollection({scene: viewer.scene, ...}) |
| 增删标签后性能骤降 | 频繁单次增删,触发多次缓冲区重写 | 批量增删后统一渲染,或用 show 替代增删 |
| 混合模式设置后无效果 | 标签透明度与混合模式不匹配 | 确保所有标签符合 OPAQUE/TRANSLUCENT 特性 |
| 局部坐标系标签位置错误 | modelMatrix 计算错误 |
使用 Cesium.Transforms.eastNorthUpToFixedFrame 生成正确矩阵 |
总结
- LabelCollection 是 Cesium 中批量管理标签的高性能方案,适合大量标签场景,核心优势是批量渲染、低内存占用、支持局部坐标系;
- 关键优化点:按更新频率拆分 Collection、选择合适的
blendOption、用show替代频繁增删、批量操作后统一渲染; - 与 Entity 对比:少量标签用 Entity 快速开发,大量/动态标签用 LabelCollection 保证性能。
书签栏