cesium 中 primitive 数据加载以及数据位置信息更新方法

817 阅读3分钟

通用更新技巧

  1. 部分属性更新(如颜色):

    const attributes = primitive.getGeometryInstanceAttributes(instance);
    attributes.color = newColorValue;
    
  2. 完全替换几何体(如位置/形状变化):

    • 重新创建 GeometryInstance 并赋值给 primitive.geometryInstances
  3. 批量更新(多个实例):

    const instances = [instance1, instance2];
    primitive.geometryInstances = instances; // 一次性更新所有实例
    

1. Primitive 数据加载

基本步骤:

// 创建几何实例(GeometryInstance)
const instance = new Cesium.GeometryInstance({
  geometry: new Cesium.RectangleGeometry({
    rectangle: Cesium.Rectangle.fromDegrees(-120.0, 30.0, -100.0, 40.0),
    vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  }),
  id: 'dynamicRect', // 唯一标识符(用于后续更新)
  attributes: {
    color: new Cesium.ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0) // 红色
  }
});

// 创建 Primitive 并添加到场景
const primitive = new Cesium.Primitive({
  geometryInstances: instance,
  appearance: new Cesium.PerInstanceColorAppearance()
});
viewer.scene.primitives.add(primitive);

支持的数据类型:

  • 内置几何RectangleGeometryPolygonGeometryEllipseGeometryBoxGeometrySphereGeometry 等
  • 自定义几何:通过 Geometry 和 GeometryAttribute 构建
  • 3D 模型:使用 Model 类(非 Primitive,但可单独加载)

2. 位置信息动态更新

方法 1:直接更新模型矩阵(推荐)

// 获取 Primitive 中的实例属性
const attributes = primitive.getGeometryInstanceAttributes('dynamicRect');

// 创建新位置(示例:移动矩形)
const newRectangle = Cesium.Rectangle.fromDegrees(-110.0, 35.0, -90.0, 45.0);

// 计算新位置的模型矩阵
const modelMatrix = Cesium.Matrix4.fromTranslation(
  Cesium.Cartesian3.fromDegrees(-100.0, 35.0, 0), // 中心点
  new Cesium.Matrix4()
);

// 更新模型矩阵并标记需要刷新
attributes.modelMatrix = modelMatrix;
attributes.modelMatrix.needsUpdate = true; // 关键步骤!

方法 2:重建 GeometryInstance(简单但性能较低)

// 移除旧 Primitive
viewer.scene.primitives.remove(primitive);

// 创建新实例
const newInstance = new Cesium.GeometryInstance({
  geometry: new Cesium.RectangleGeometry({
    rectangle: Cesium.Rectangle.fromDegrees(-115.0, 32.0, -95.0, 42.0),
    vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  }),
  attributes: {
    color: new Cesium.ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 1.0) // 蓝色
  }
});

// 重新创建 Primitive
primitive = new Cesium.Primitive({
  geometryInstances: newInstance,
  appearance: new Cesium.PerInstanceColorAppearance()
});
viewer.scene.primitives.add(primitive);

3. 动态更新其他属性

更新属性

// 更新颜色
const attributes = pointPrimitive.getGeometryInstanceAttributes(instance);
attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.BLUE);

// 更新位置(需重新创建实例)
primitive.geometryInstances = new Cesium.GeometryInstance({
  geometry: new Cesium.PointGeometry({
    position: Cesium.Cartesian3.fromDegrees(-75.0, 40.5),
    pointSize: 15
  }),
  attributes: { color: attributes.color } // 保留原颜色
});

修改颜色:

const attributes = primitive.getGeometryInstanceAttributes('dynamicRect');
attributes.color = [0, 1, 0, 1]; // RGBA 绿色
attributes.color.needsUpdate = true;

显示/隐藏:

attributes.show = 0; // 0=隐藏, 1=显示
attributes.show.needsUpdate = true;

4. 性能优化技巧

  1. 批量更新:对多个实例使用 PrimitiveCollection

    const collection = new Cesium.PrimitiveCollection();
    collection.add(primitive1);
    collection.add(primitive2);
    // 添加/移除元素 
    viewer.scene.primitives.add(collection);
    viewer.scene.primitives.remove(collection);
    

    批量渲染:将多个几何实例合并到一个 Primitive 中。

    const primitive = new Cesium.Primitive({
      geometryInstances: [pointInstance, polylineInstance], // 批量添加
      appearance: /* 统一外观 */
    });
    
  2. 避免频繁更新:静态数据优先使用 GroundPrimitive 或 Entity

  3. 复用 Primitive:优先更新 modelMatrix 而非重建

  4. 使用 WebWorker:复杂计算在后台线程进行

    const worker = new Worker('computeWorker.js');
    worker.postMessage(positions);
    worker.onmessage = updatePrimitive;
    
  5. 按需更新:通过 show 属性控制可见性,减少渲染负担

  6. 销毁对象

viewer.scene.primitives.remove(primitive);
primitive.destroy(); // 释放内存
  1. 共享外观提升性能
const sharedAppearance = new Cesium.PerInstanceColorAppearance();

const primitive1 = new Cesium.Primitive({ 
  geometryInstances: [...], 
  appearance: sharedAppearance 
});

const primitive2 = new Cesium.Primitive({ 
  geometryInstances: [...], 
  appearance: sharedAppearance 
});

5. 常见问题解决

  • 更新无效?  确认已设置 needsUpdate = true

  • 闪烁问题?  使用 requestAnimationFrame 确保在渲染前完成更新

    Cesium.requestAnimationFrame(() => {
      attributes.modelMatrix = updatedMatrix;
      attributes.modelMatrix.needsUpdate = true;
    });
    
  • 性能瓶颈?  减少不必要的属性更新,合并几何实例


示例:动态移动矩形

let angle = 0;
function updatePosition() {
  angle += 0.02;
  
  // 计算新中心点(圆形轨迹)
  const x = -100 + 10 * Math.cos(angle);
  const y = 35 + 10 * Math.sin(angle);
  const center = Cesium.Cartesian3.fromDegrees(x, y);
  
  // 更新模型矩阵
  const attributes = primitive.getGeometryInstanceAttributes('dynamicRect');
  attributes.modelMatrix = Cesium.Matrix4.fromTranslation(center, new Cesium.Matrix4());
  attributes.modelMatrix.needsUpdate = true;
  
  requestAnimationFrame(updatePosition);
}
updatePosition();

提示:对于复杂场景(如数千个动态对象),考虑使用 CustomShader 或 GeometryUpdater 获得更高性能。

对比 Entity API

特性Primitive APIEntity API
性能⭐⭐⭐⭐ 高(直接控制渲染)⭐⭐ 中(通过DataSource抽象)
灵活性⭐⭐⭐⭐⭐ 完全自定义⭐⭐⭐ 声明式,易用
动态更新复杂度⭐⭐ 需手动管理⭐⭐⭐⭐ 自动更新
适用场景大量动态图形、自定义Shader、高性能需求常规实体、数据绑定

通过 Primitive API 可直接控制底层渲染细节,适合高性能场景,但需要手动管理更新。对于简单应用,推荐使用更易用的 Entity API