首页 / 专栏 / Cesium / Cesium LabelCollection 深度教程:高性能批量标签渲染

Cesium LabelCollection 深度教程:高性能批量标签渲染

  • Published: 2026-02-23 20:29:19
  • Tags: cesium label 标签
  • Summary: 从核心概念、使用场景、API 详解到性能优化,全方位带你掌握这个用于**批量管理和渲染标签**的核心类,特别聚焦它与单个 Label/Entity 的区别和高性能使用方式。

Scan on mobile

一、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 状态切换;
  • 统一配置:支持对整个集合设置 showmodelMatrixblendOption 等全局属性;
  • 高效增删:虽然增删标签会触发缓冲区重写,但整体效率远高于多个独立 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 核心步骤解析

  1. 创建 Collectionnew Cesium.LabelCollection(options) 需传入 scene(若使用高度参考/深度测试);
  2. 添加到场景:必须通过 scene.primitives.add() 将 Collection 加入场景,否则标签不会显示;
  3. 添加标签:通过 add() 方法添加单个标签,返回 Label 实例可后续修改;
  4. 生命周期管理:可通过 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 生成正确矩阵

总结

  1. LabelCollection 是 Cesium 中批量管理标签的高性能方案,适合大量标签场景,核心优势是批量渲染、低内存占用、支持局部坐标系;
  2. 关键优化点:按更新频率拆分 Collection、选择合适的 blendOption、用 show 替代频繁增删、批量操作后统一渲染;
  3. 与 Entity 对比:少量标签用 Entity 快速开发,大量/动态标签用 LabelCollection 保证性能。

More in category