经纬志
首页 / 实战手册 / 3D 与 Cesium

Entity 上了两千个,帧率掉到 18

先看结论

五百个站点时很流畅,加到两千个站点后拖动明显卡顿,性能面板里 update 阶段占了大头。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

打开 scene.debugShowFramesPerSecond,帧率从 60 掉到 18–22。 Chrome 性能面板显示每帧 EntityCluster 与 Property.getValue 占用 20 ms 以上,而 draw call 数量并不高。

viewer.scene.debugShowFramesPerSecond = true;
// 左上角显示 18 FPS

原因

Entity 是一层便利封装:位置、朝向、颜色、显隐都可能是 Property 对象,每帧都要对每个实体求值一次。 两千个实体意味着每帧两万次以上的求值,再叠加 Label 的 文字纹理重建,CPU 时间就被吃光了。

Label 的问题更隐蔽:每个标签是一张独立的纹理, 视角变化时还可能重新生成字形图集,数量一多就是灾难。

排查过程

  1. 先只保留 Billboard,把 Label 注释掉,看帧率是否回升,以定位是标签还是图标。
  2. 读 viewer.dataSources 的实体总数,确认不是重复添加。
  3. 检查有没有给每个实体单独设置 ConstantProperty,可以合并为共享属性。
console.log('实体数量', viewer.entities.values.length);
console.log('图元数量', viewer.scene.primitives.length);

解决方案

用 BillboardCollection 代替 Entity。一次 add 两千个广告牌, 只产生一个图元、一次 draw call:

var collection = new Cesium.BillboardCollection({
  scene: viewer.scene
});
viewer.scene.primitives.add(collection);

var icon = '/assets/icons/station.png';

stations.forEach(function (s) {
  collection.add({
    position: Cesium.Cartesian3.fromDegrees(s.lng, s.lat, 0),
    image: icon,
    scale: 0.8,
    verticalOrigin: Cesium.VerticalOrigin.BOTTOM
  });
});

标签同理,用 LabelCollection,并关闭不必要的描边与背景:

var labels = new Cesium.LabelCollection();
viewer.scene.primitives.add(labels);

labels.add({
  position: Cesium.Cartesian3.fromDegrees(116.391, 39.907, 0),
  text: '北京南站',
  font: '14px sans-serif',
  fillColor: Cesium.Color.WHITE,
  style: Cesium.LabelStyle.FILL,
  pixelOffset: new Cesium.Cartesian2(0, -28),
  disableDepthTestDistance: Number.POSITIVE_INFINITY
});

想要保留 Entity 的写法,就把动态属性改成常量,并开启集群:

viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(116.391, 39.907, 0),  // 直接给 Cartesian3
  billboard: {
    image: icon,
    scale: 0.8
  }
});

viewer.dataSources.add(new Cesium.CustomDataSource('stations'));
viewer.scene.globe.enableLighting = false;

验证

把两千个点重新加载后,FPS 应从 18 回到 50 以上; 在性能面板里 update 阶段耗时降到 5 ms 以内。 用 scene.primitives.length 确认只增加了一两个集合,而不是两千个图元。

折中做法:交互频繁、数量少的重点站点继续用 Entity, 底图上大量普通站点走 BillboardCollection。两套并存不会互相干扰, 按数量分层是最省改动的方案。

引用本文

经纬志(2026)。《Entity 上了两千个,帧率掉到 18》。https://www.jingweizhi.com/cookbook/cesium-entity-drop-frame.html(访问日期 2026-11-03)。