Cesium快速入门到精通系列教程十一:Cesium1.74中高性能渲染上万Polyline

发布于:2025-06-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

在Cesium 1.74中,高性能渲染大量线条的核心在于​​Primitive API的批量处理​​、​​着色器优化​​和​​数据合并策略​​。以下是结合多个技术方案的最佳实践和完整代码实现:

一、高性能渲染方案选择

Primitive API批量渲染​​

优势​​:直接操作几何体实例,减少Entity的开销,支持合并几何数据降低Draw Call。

关键类​​:PolylineGeometry + GeometryInstance + Primitive。

​​动态流光效果​​

通过GLSL着色器实现流动材质,避免JavaScript频繁更新。

​​数据分块与LOD​​

对超大规模数据(如城市路网)按视距动态加载简化模型。

静态线条批量渲染(万级线条)​​完整代码实现:

const viewer = new Cesium.Viewer('cesiumContainer');

// 1. 生成测试数据:1万条随机线段
const lineCount = 10000;
const instances = [];
for (let i = 0; i < lineCount; i++) {
  const startLon = -180 + Math.random() * 360;
  const startLat = -90 + Math.random() * 180;
  const endLon = startLon + Math.random() * 10 - 5;
  const endLat = startLat + Math.random() * 10 - 5;
  
  instances.push(new Cesium.GeometryInstance({
    geometry: new Cesium.PolylineGeometry({
      positions: Cesium.Cartesian3.fromDegreesArray([startLon, startLat, endLon, endLat]),
      width: 1.0,
      vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
    }),
    attributes: {
      color: new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 0.0, 1.0) // 绿色线条
    }
  }));
}

// 2. 批量渲染
const primitive = new Cesium.Primitive({
  geometryInstances: instances,
  appearance: new Cesium.PolylineColorAppearance({
    translucent: false
  }),
  asynchronous: false // 同步加载确保立即渲染
});

viewer.scene.primitives.add(primitive);

二、为每个线条定义颜色

在Cesium 1.74中,要为每条线条定义不同的颜色,可以通过修改GeometryInstance的attributes.color属性,为每个实例分配随机或特定的颜色值。以下是具体实现方法和完整代码:

关键修改点

1、ColorGeometryInstanceAttribute动态赋值​​

在循环中为每条线条生成随机颜色(RGBA格式),替换原有的固定绿色值。

​​2、确保使用PolylineColorAppearance​​

必须设置vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT以支持顶点颜色。

完整代码(每条线条随机颜色)

const viewer = new Cesium.Viewer('cesiumContainer');

// 1. 生成测试数据:1万条随机线段(每条颜色不同)
const lineCount = 10000;
const instances = [];
for (let i = 0; i < lineCount; i++) {
  const startLon = -180 + Math.random() * 360;
  const startLat = -90 + Math.random() * 180;
  const endLon = startLon + Math.random() * 10 - 5;
  const endLat = startLat + Math.random() * 10 - 5;
  
  // 为每条线生成随机颜色(RGBA)
  const r = Math.random(); // 红色分量 [0,1]
  const g = Math.random(); // 绿色分量
  const b = Math.random(); // 蓝色分量
  const a = 1.0;          // 不透明度(1为完全不透明)

  instances.push(new Cesium.GeometryInstance({
    geometry: new Cesium.PolylineGeometry({
      positions: Cesium.Cartesian3.fromDegreesArray([startLon, startLat, endLon, endLat]),
      width: 1.0,
      vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT // 必须启用顶点颜色
    }),
    attributes: {
      color: new Cesium.ColorGeometryInstanceAttribute(r, g, b, a) // 动态颜色
    }
  }));
}

// 2. 批量渲染(使用支持顶点颜色的外观)
const primitive = new Cesium.Primitive({
  geometryInstances: instances,
  appearance: new Cesium.PolylineColorAppearance({
    translucent: false // 非透明渲染
  }),
  asynchronous: false // 同步加载
});

viewer.scene.primitives.add(primitive);

三、对上万条线高性能更新

在Cesium 1.74中,高性能更新上万条线条的核心在于​​减少渲染管线开销​​和​​优化数据更新机制​​。以下是针对该场景的完整优化方案和代码实现:

优化策略

1、​​使用Primitive API替代Entity​​

Entity API适合少量动态对象,而Primitive直接操作几何体实例,更适合大规模数据更新。

​​2、批量更新几何体属性​​

通过修改GeometryInstance的attributes或重建Primitive实现全量更新,避免逐条操作。

​​3、着色器动态控制​​

对需要动态效果(如颜色变化)的线条,通过着色器Uniform变量控制,减少CPU-GPU通信。

​​4、数据分块与按需更新​​

将线条按空间区域分块,仅更新可见区域或变化部分。

全量更新所有线条位置​​完整代码:

  const viewer = new Cesium.Viewer("cesiumContainer");

  // 1. 生成测试数据:1万条随机线段
  const lineCount = 10000;
  const instances = [];
  for (let i = 0; i < lineCount; i++) {
    const startLon = -180 + Math.random() * 360;
    const startLat = -90 + Math.random() * 180;
    const endLon = startLon + Math.random() * 10 - 5;
    const endLat = startLat + Math.random() * 10 - 5;

    instances.push(
      new Cesium.GeometryInstance({
        geometry: new Cesium.PolylineGeometry({
          positions: Cesium.Cartesian3.fromDegreesArray([
            startLon,
            startLat,
            endLon,
            endLat,
          ]),
          width: 1.0,
          vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
        }),
        attributes: {
          color: new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 0.0, 1.0), // 绿色线条
        },
      })
    );
  }

  // 初始化Primitive(原代码)
  let primitive = viewer.scene.primitives.add(
    new Cesium.Primitive({
      geometryInstances: instances,
      appearance: new Cesium.PolylineColorAppearance({ translucent: false }),
      asynchronous: false,
    })
  );

  // 2、更新函数:重新生成所有线条位置
  function updateAllLines() {
    const newInstances = [];
    for (let i = 0; i < lineCount; i++) {
      const startLon = -180 + Math.random() * 360;
      const startLat = -90 + Math.random() * 180;
      const endLon = startLon + Math.random() * 10 - 5;
      const endLat = startLat + Math.random() * 10 - 5;

      newInstances.push(
        new Cesium.GeometryInstance({
          geometry: new Cesium.PolylineGeometry({
            positions: Cesium.Cartesian3.fromDegreesArray([
              startLon,
              startLat,
              endLon,
              endLat,
            ]),
            width: 1.0,
            vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
          }),
          attributes: {
            color: new Cesium.ColorGeometryInstanceAttribute(
              Math.random(),
              Math.random(),
              Math.random(),
              1.0
            ), // 随机颜色
          },
        })
      );
    }

    // 高性能更新:先移除旧Primitive,再添加新Primitive
    viewer.scene.primitives.remove(primitive);
    primitive = new Cesium.Primitive({
      geometryInstances: newInstances,
      appearance: new Cesium.PolylineColorAppearance({ translucent: false }),
      asynchronous: false,
    });
    viewer.scene.primitives.add(primitive);
  }

  // 触发更新(例如每2秒更新一次)
  setInterval(updateAllLines, 2000);


网站公告

今日签到

点亮在社区的每一天
去签到