Cesium Primitive 全面解析与实践(一)「10 分钟掌握 Cesium Primitive」

Cesium Primitive 全面解析

🚀 个人简介:某大型测绘遥感企业资深Webgis开发工程师,软件设计师(中级)、优快云优质创作者
💟 作 者:柳晓黑胡椒❣️
📝 专 栏:再识Cesium
🌈 若有帮助,还请关注点赞收藏,不行的话我再努努力💪💪💪

本文基于 Cesium 1.132 版本进行演示,其他版本在 API 上可能略有不同。

本文整理了常见的primtive应用,配合示例代码,你可以在实际项目中直接使用或二次封装,提升开发效率。
✨ 欢迎大家在评论区提出建议或交流心得,如果需要完整源码,可以私聊我获取。

Primitive 是什么

在这里插入图片描述

一、Primitive 是什么

在 Cesium 中,Primitive 是最底层的渲染单元,它直接和 WebGL 渲染管线 打交道。
如果把 Cesium 比作一栋大楼:

  • Entity 就像是“装修后的房子”,拿来即用,方便开发。
  • Primitive 就像是“钢筋混凝土结构”,更接近底层,可以自由搭建,但需要更多代码。

1. 官方定义

Primitive 是 由几何(Geometry)+ 外观(Appearance)组合而成的渲染对象

  • Geometry 决定了形状(比如盒子、球体、多边形)。
  • Appearance 决定了外观(颜色、纹理、材质、光照)。
    两者结合,就能把一个抽象的几何体真正绘制到地球场景中。

2. 为什么需要 Primitive?

Cesium 最早就是围绕 Primitive 构建的,Entity 其实只是对 Primitive 的封装。

  • Entity = 上层封装,快速开发
  • Primitive = 底层实现,性能优先

换句话说,所有 Entity 最终都会被拆解为一个或多个 Primitive 才能渲染。
当你的数据量很小,用 Entity 就够了;但当需要渲染 几十万甚至上百万个对象 时,Primitive 能显著提升性能。


3. Primitive 的生命周期

一个 Primitive 在 Cesium 中的典型流程:

  1. 构造 Geometry(定义形状、顶点、索引)。
  2. 指定 Appearance(定义着色方式、纹理、材质)。
  3. 交给 Primitive 对象,加入 scene.primitives 中。
  4. Cesium 会在渲染循环中把它转换成 WebGL 缓冲区和着色器,最终绘制到画布上。

4. 与 Entity 的关系

可以把 Entity 看成是对 Primitive 的 一层语法糖

  • Entity:封装了属性(position、material、orientation…),让开发者更容易上手。
  • Primitive:直接操作几何和渲染参数,更灵活,但写法更复杂。

Primitive 的优点 & 与 Entity 的区别

👉 Entity = 开发效率优先,Primitive = 性能与灵活性优先。

1. Primitive 的优点

Primitive 的核心优势在于 性能与灵活性

  • 高性能渲染

    • Entity 是对 Primitive 的封装,Cesium 会帮你自动维护各种属性(位置、材质、时间动态等)。
    • 当数据量很大(比如几十万点),Entity 管理开销非常大,而 Primitive 更接近底层,直接走 WebGL 管线,性能更高。
  • 批量绘制(Batching)

    • Primitive 支持 Instance,可以把多个几何对象合并为一个 Primitive 提交给 GPU,大大减少绘制开销。
    • 例如渲染 10 万个点时,Entity 会创建 10 万个对象,而 Primitive 可以一次性传给 GPU。
  • 灵活的渲染控制

    • 可以直接自定义 Geometry(顶点、索引、法线)和 Appearance(着色器)。
    • 支持更复杂的效果,比如自定义 GLSL Shader,光照算法,甚至实现特殊材质。
  • 底层可扩展性

    • Primitive 是 Cesium 的基础设施,所有高层功能(Entity、DataSource)最终都会转成 Primitive 来渲染。
    • 如果你需要突破 Entity 的限制,就必须使用 Primitive。

2. Entity 与 Primitive 的区别

对比维度EntityPrimitive
定位高层封装,业务友好底层渲染,高性能优化
开发难度简单,几行代码即可较复杂,需要理解 Geometry & Appearance
性能小规模数据表现好大规模数据优势明显
动态属性内置支持时间动态(SampledProperty 等)需手动实现
渲染控制封装完善,可快速调用灵活度高,可自定义 Shader
适用场景中小规模应用,快速原型开发海量数据、特殊可视化、性能优化

3. 如何选择?

  • 优先使用 Entity
    如果你的项目是业务导向、数据量不大(几千以内)、追求开发效率。

  • 使用 Primitive
    如果你的项目需要渲染 大规模数据(>10万),或者要做 特殊渲染效果(自定义着色、特殊几何)


Primitive 构成

在 Cesium 的渲染体系中,一个 Primitive = Geometry + Appearance

  • Geometry(几何):决定物体的形状、空间位置和顶点信息(物体“长成什么形状”)。
  • Appearance(外观):决定物体的材质、颜色、纹理和着色方式(物体“看起来怎么样”)。
    在这里插入图片描述

Geometry

  • 负责描述物体的结构和顶点数据。
  • 常见内置几何:BoxGeometry、PolygonGeometry、SphereGeometry 等。
  • 一个 Geometry 包含:
    • 顶点(Vertices):几何形状的空间坐标点。
    • 索引(Indices):定义顶点之间的连接关系。
    • 法线(Normals):用于光照计算。
    • 纹理坐标(UV):控制贴图如何映射到表面。

👉 举例:BoxGeometry 会生成一个立方体的顶点和索引;PolygonGeometry 会生成多边形的边和面。
在这里插入图片描述

Appearance

  • 负责描述几何体“长什么样子”。
  • 内置的 Appearance 有:
    • MaterialAppearance:使用材质系统(支持颜色、图片纹理、渐变、光照)。
    • PerInstanceColorAppearance:为每个实例单独指定颜色,性能较高。
    • EllipsoidSurfaceAppearance:适用于地表贴图。
    • PolylineMaterialAppearance:用于线,支持虚线、箭头等。

👉 Appearance 的本质是 一个着色器(Shader),你甚至可以自己写 GLSL Shader 来实现特殊效果(比如发光、扫描、流动)。
在这里插入图片描述

Primitive 应用

1.添加单个实例

👉 示例说明:添加一个蓝色的圆形 Primitive

const primitiveCollection = new Cesium.PrimitiveCollection()
const circle = new Cesium.CircleGeometry({center: Cesium.Cartesian3.fromDegrees(114.347137, 30.541429, 100), radius: 200.0});
const geometry = Cesium.CircleGeometry.createGeometry(circle);
const instance = new Cesium.GeometryInstance({geometry: geometry,});
primitiveCollection.add(new Cesium.Primitive({
  geometryInstances: instance,
  asynchronous: false, // 关闭异步
  appearance: new Cesium.MaterialAppearance({
    material: new Cesium.Material({
      fabric: {
        type: "Color",
        uniforms: {color: Cesium.Color.BLUE}
      }
    })
  })
}));
const boundingSphere = geometry.boundingSphere; // 获取几何体的包围球
viewer.camera.flyToBoundingSphere(boundingSphere);

在这里插入图片描述

2.添加多几何不同外观实例

👉 示例说明:批量添加 10 万个立方体,每个实例都有不同颜色

const primitiveCollection = new Cesium.PrimitiveCollection()
const instances = [];
const positions = []; // 记录用于计算 boundingSphere
let boxGeometry = Cesium.BoxGeometry.fromDimensions({dimensions: new Cesium.Cartesian3(100, 100, 100)})
for (let i = 0; i < 100000; i++) {
  const position = Cesium.Cartesian3.fromDegrees(114.347137 + Math.random(), 30.541429 + Math.random(), 200 + Math.random() * 100)
  const instance = new Cesium.GeometryInstance({
    geometry: boxGeometry,
    modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(position),//通过modelMatrix设置不同的位置
    id: "BoxGeometry" + i,
    // 每个实例几何颜色得值和类型信息
    attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({alpha: 1}))}
  });
  instances.push(instance);
  positions.push(position)
}
primitiveCollection.add(new Cesium.Primitive({
  geometryInstances: instances,
  // appearance: new Cesium.EllipsoidSurfaceAppearance({material: Cesium.Material.fromType('Color')}),
  appearance: new Cesium.PerInstanceColorAppearance({flat: true, translucent: false})// 具有颜色属性得geometryInstance实例的外观
}));
// 计算一个包含笛卡尔点坐标得紧合边界球
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
viewer.camera.flyToBoundingSphere(boundingSphere);

在这里插入图片描述

3.添加大量点

👉 示例说明:批量绘制全球范围内的点位,每个点有随机颜色和图标

const billboardsCollection = new Cesium.BillboardCollection()
const color = () => new Cesium.Color(Math.random(), Math.random(), Math.random(), 1); // 随机颜色
  for (let longitude = -180; longitude < 180; longitude++) {
    for (let latitude = -90; latitude < 90; latitude++) {
      billboardsCollection.add({
        position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
        image: png5, // 图标
        scale: 0.5, // 调整图标的大小
        color: color(), // 随机颜色
        id: 'billboard' + '-' + longitude + '-' + latitude
      })
    }
  }

在这里插入图片描述

4.添加大量线面

👉 示例说明:全球范围内绘制上万条线和多边形面,使用不同颜色区分。

const instances1 = [];
const instances2 = [];
for (let i = 0; i < 10000; i++) {
  const longitude = Math.random() * 360 - 180;
  const latitude = Math.random() * 180 - 90;
  const positions = [longitude, latitude, longitude + Math.random(), latitude, longitude, latitude + Math.random()];
  const lineInstance = new Cesium.GeometryInstance({
    geometry: new Cesium.PolylineGeometry({
      positions: Cesium.Cartesian3.fromDegreesArray(positions),
      width: 3,
      vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
    }),
    attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(i % 2 == 0 ? 'green' : 'red').withAlpha(1))},
    id: 'line' + i
  });
  const faceInstance = new Cesium.GeometryInstance({
    geometry: new Cesium.PolygonGeometry({
      polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(positions)),
      height: 0,
      vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
    }),
    attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(i % 2 == 0 ? 'red' : 'green').withAlpha(1))},
    id: 'face' + i
  })
  instances1.push(lineInstance);
  instances2.push(faceInstance);
}
primitiveCollection.add(new Cesium.Primitive({
  geometryInstances: instances1,
  appearance: new Cesium.PolylineColorAppearance()
}));
primitiveCollection.add(new Cesium.Primitive({
  geometryInstances: instances2,
  appearance: new Cesium.PerInstanceColorAppearance({closed: true})
}));

在这里插入图片描述

5.添加大量曲线

👉 示例说明:全球范围内批量绘制上百条随机曲线,每条曲线带有不同的颜色。

const instances = [];
const getColor = () => '#' + Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, '0')
for (let i = 0; i < 300; i++) {
  const positions = Array.from({length: 10}, () => Math.random() * 360 - 180).reduce((acc, cur) => acc.concat(cur), [])
  const instance = new Cesium.GeometryInstance({
    geometry: new Cesium.PolylineGeometry({
      positions: generateCurvePoints(positions, 20),
      width: 2,
      vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
    }),
    attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(getColor()).withAlpha(0.6))},
    id: "curve" + i
  })
  instances.push(instance)
}
primitiveCollection.add(new Cesium.Primitive({
  geometryInstances: instances,
  appearance: new Cesium.PolylineColorAppearance()
}));

在这里插入图片描述

6.添加大量立方体

👉 示例说明:全球范围内绘制上万个半透明的立方体

const instances = [];
for (let i = 0; i < 10000; i++) {
  const longitude = Math.random() * 360 - 180;
  const latitude = Math.random() * 180 - 90;
  const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0);
  const dimensions = new Cesium.Cartesian3(40000.0, 30000.0, 500000.0);
  const color = Cesium.Color.RED.withAlpha(0.2);
  instances.push(new Cesium.GeometryInstance({
    geometry: new Cesium.BoxGeometry.fromDimensions({
      vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
      dimensions: dimensions
    }),
    modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(position),
    attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)}
  }));
}
primitiveCollection.add(new Cesium.Primitive({
  geometryInstances: instances,
  appearance: new Cesium.PerInstanceColorAppearance()
}));

在这里插入图片描述

Takeaways

在这一篇中,我们系统介绍了 Primitive 的概念、优势、基本构成以及常见使用示例。通过这些例子,你应该已经能感受到 Primitive 相较于 Entity 在性能和灵活性上的差异,也对 Geometry 与 Appearance 的组合有了更直观的理解。

不过,Primitive 的强大远不止于此。下一节我们将深入 Primitive 的几何类型 Geometry,并进一步探讨 如何使用自定义顶点来构建底层 Primitive。这一部分会更贴近图形学的底层逻辑,例如顶点、索引、法线等内容,非常适合对 Cesium 内部渲染机制感兴趣的同学

AI智能图表创作平台,轻松对话绘图 Next AI Draw.io 是款融合大语言模型 draw.io 的创新型图表绘制平台。无需掌握复杂的绘图规则,只需通过自然语言输入,即可完成图表构建、修改增强,帮助开发者和可视化创作者大幅提升效率。无论你是想绘制 AWS 架构图、GCP 拓扑,还是个带有动画连接器的系统结构图,这款工具都能通过智能对话快速呈现。 核心亮点 LLM驱动的图表构建 通过 Chat 接口 AI 对话,快速生成符合语义的图表,轻松支持 draw.io XML 格式解析。 图像复制增强 上传张已有图表或架构草图,AI 自动别结构并重建图表,可进步优化样式或内容。 图表版本管理 内置图表历史记录系统,支持版本切换回滚,便于团队协作修改回溯。 交互式绘图对话体验 内置对话界面,可边聊边画图,所见即所得,轻松优化图表结构排版。 多云架构模板键生成 支持 AWS、GCP、Azure 架构图自动生成,适配图标库,适合开发、运维、架构师使用。 GCP架构图 动画连接器 支持为图表元素添加动态连接器,提升图表交互性演示感。 技术架构支持 Next.js:提供稳定高性能的前端体验 Vercel AI SDK:整合流式对话多模型支持 react-drawio:实现图表编辑可视化渲染 多模型接入:支持 OpenAI、Anthropic、Google、Azure、DeepSeek、Ollama 等主流 AI API claude-sonnet-4-5 专项训练:在 AWS 架构图任务上表现优异
Cesium Primitive创建椭圆时,可借助`EllipseGeometry`来定义椭圆的几何形状,再通过`Primitive`将其添加到场景中。以下是相关参数说明和示例代码。 ### 参数说明 - `center`:椭圆中心。 - `semiMajorAxis`:长半轴。 - `semiMinorAxis`:短半轴。 - `height`:椭圆几何的高度。 - `extrudedHeight`:拉伸高度 [^5]。 ### 示例代码 #### 示例 ```javascript const primitive = new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: new Cesium.EllipseGeometry({ center: Cesium.Cartesian3.fromDegrees(-100.0, 20.0), semiMinorAxis: 500000.0, semiMajorAxis: 1000000.0, rotation: Cesium.Math.PI_OVER_FOUR, vertexFormat: Cesium.VertexFormat.POSITION_AND_ST }) }), appearance: new Cesium.EllipsoidSurfaceAppearance({ material: Cesium.Material.fromType('Stripe') }) }); viewer.scene.primitives.add(primitive); ``` 此示例创建了个基本的椭圆图元,设置了椭圆的中心、长短半轴、旋转角度和外观材质 [^1]。 #### 示例二 ```javascript const ellipse = new Cesium.EllipseGeometry({ center: Cesium.Cartesian3.fromDegrees(110.0, 30.0, 500), semiMajorAxis: 500.0, semiMinorAxis: 1500.0, height: 300, extrudedHeight: 800 }); ``` 该示例创建了个可设置拉伸高度的椭圆 [^2]。 #### 示例三 ```javascript const circle = new Cesium.EllipseGeometry({ center: Cesium.Cartesian3.fromDegrees(114.347137, 30.541429), semiMajorAxis: 1500, semiMinorAxis: 500, height: 100, extrudedHeight: 50 }); const geometry = Cesium.EllipseGeometry.createGeometry(circle); const instance = new Cesium.GeometryInstance({ geometry: geometry }); primitiveCollection.add(new Cesium.Primitive({ geometryInstances: instance, asynchronous: false, appearance: new Cesium.MaterialAppearance({ material: new Cesium.Material({ fabric: { type: 'Color', uniforms: { color: Cesium.Color.RED } } }) }) })); viewer.camera.flyToBoundingSphere(geometry.boundingSphere); ``` 这个示例展示了如何创建椭圆几何、实例化并添加到`Primitive`集合中,同时设置了外观材质为红色 [^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳晓黑胡椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值