关于 cesiumjs-primitives
面向 CesiumJS 开发者的领域技能,说明低层 Primitive 几何、外观与批处理的使用方式。还涵盖缓冲集合和 GeoJSON 原语等面向大量矢量数据的路径。
主要功能
- 01Primitive 几何与外观配置
- 02批处理多个几何实例
- 03更新实例属性与可见性
- 04缓冲原语集合
- 05GeoJSON 原语加载
适用场景
- 01构建高性能静态几何场景
- 02批量渲染圆柱等体积图形
- 03加载大型静态 GeoJSON 数据集
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cesiumgs/ cesiumjs-skills --skill cesiumjs-primitives安装后在 Claude Code 中输入/cesiumjs-primitives确认已加载。
详细介绍
CesiumJS 图元与几何体
适用范围: CesiumJS v1.144+(ES 模块导入,使用
??替代defaultValue)
架构
Primitive API 是 Entity API 底层的低级渲染层,以牺牲便捷性换取性能。
核心公式: Primitive = GeometryInstance[] + Appearance
- GeometryInstance——在世界空间中定位 Geometry,并设置每个实例的属性(颜色、显示状态)。
- Geometry——描述形状的顶点数据(多边形、立方体、椭球体等)。
- Appearance——用于着色几何体的 GLSL 着色器、渲染状态,以及可选的 Material。
Primitive 首次渲染后不可变——几何体无法更改,但可通过 primitive.getGeometryInstanceAttributes(id) 更新每个实例的属性。
Primitive
import {
Viewer, Primitive, GeometryInstance, EllipseGeometry,
EllipsoidSurfaceAppearance, Material, Cartesian3, Math as CesiumMath,
} from "cesium";
const viewer = new Viewer("cesiumContainer");
const scene = viewer.scene;
const primitive = scene.primitives.add(new Primitive({
geometryInstances: new GeometryInstance({
geometry: new EllipseGeometry({
center: Cartesian3.fromDegrees(-100.0, 40.0),
semiMinorAxis: 250000.0,
semiMajorAxis: 400000.0,
rotation: CesiumMath.PI_OVER_FOUR,
vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, // must match appearance
}),
id: "myEllipse", // returned by Scene.pick()
}),
appearance: new EllipsoidSurfaceAppearance({ material: Material.fromType("Stripe") }),
}));
主要选项
| 选项 | 默认值 | 用途 |
|---|---|---|
geometryInstances | -- | 单个实例或实例数组 |
appearance | -- | 着色(Appearance 子类) |
show | true | 切换可见性 |
modelMatrix | Matrix4.IDENTITY | 变换所有实例 |
asynchronous | true | 在 Web Worker 上构建几何体 |
releaseGeometryInstances | true | GPU 上传后释放几何体 |
allowPicking | true | 设为 false 可节省 GPU 内存 |
shadows | ShadowMode.DISABLED | 投射/接收阴影 |
批处理多个实例
同一个 Primitive 中的所有实例共用一次绘制调用。
import {
Primitive, GeometryInstance, RectangleGeometry, EllipseGeometry,
PerInstanceColorAppearance, ColorGeometryInstanceAttribute,
Cartesian3, Rectangle, Color,
} from "cesium";
scene.primitives.add(new Primitive({
geometryInstances: [
new GeometryInstance({
geometry: new RectangleGeometry({
rectangle: Rectangle.fromDegrees(-140, 30, -100, 40),
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
id: "rect",
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.RED.withAlpha(0.5)) },
}),
new GeometryInstance({
geometry: new EllipseGeometry({
center: Cartesian3.fromDegrees(-80, 35),
semiMinorAxis: 200000.0,
semiMajorAxis: 300000.0,
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
id: "ellipse",
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.BLUE.withAlpha(0.5)) },
}),
],
appearance: new PerInstanceColorAppearance(),
}));
批处理体积几何体(CylinderGeometry 网格)
体积几何体(Cylinder、Box、Ellipsoid)必须通过每个 GeometryInstance 的 modelMatrix 来定位。使用 Matrix4.multiply 将世界空间锚点与局部偏移组合,然后将所有实例批处理到一个 Primitive 中。
import {
Primitive, GeometryInstance, CylinderGeometry,
PerInstanceColorAppearance, ColorGeometryInstanceAttribute,
Cartesian3, Matrix4, Transforms, Color, Math as CesiumMath,
} from "cesium";
const center = Cartesian3.fromDegrees(-73.9857, 40.7580);
const anchorFrame = Transforms.eastNorthUpToFixedFrame(center, undefined, new Matrix4());
const instances = [];
const GRID = 10;
const SPACING = 50; // metres
for (let row = 0; row < GRID; row++) {
for (let col = 0; col < GRID; col++) {
const xOffset = (col - GRID / 2) * SPACING;
const yOffset = (row - GRID / 2) * SPACING;
// Combine anchor ENU frame with a local XYZ offset
const modelMatrix = Matrix4.multiply(
anchorFrame,
Matrix4.fromTranslation(new Cartesian3(xOffset, yOffset, 100), new Matrix4()),
new Matrix4(),
);
instances.push(new GeometryInstance({
geometry: new CylinderGeometry({
length: 200,
topRadius: 8,
bottomRadius: 8,
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
modelMatrix,
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.fromRandom({ alpha: 1.0 })) },
}));
}
}
scene.primitives.add(new Primitive({
geometryInstances: instances,
appearance: new PerInstanceColorAppearance({ flat: true }),
}));
// Frame the grid so the full batch is visible -- a shallow pitch hides cylinders
// behind the foreground; a near-nadir pitch flattens them. Aim for ~-45° (-PI/4)
// at a range that covers the grid footprint (GRID * SPACING) with margin.
const range = GRID * SPACING * 3; // ~1500 m for a 10x10x50m grid
viewer.camera.lookAt(
center,
new Cartesian3(0, -range * 0.7, range * 0.7), // offset south + up for -45° pitch
);
关键模式:
Matrix4.multiply(anchorFrame, Matrix4.fromTranslation(offset, result), result)——将地理锚点处的 ENU 坐标系与局部东/北/上平移组合起来。Color.fromRandom({ alpha: 1.0 })会生成完全不透明的随机颜色,适合创建彩虹色批次。- 视角很重要: 对于垂直体积构成的网格,建议使用约
3 * gridFootprint的距离,并将俯仰角设为~-45°(-CesiumMath.PI_OVER_FOUR,约-0.785rad)。俯仰角浅于约-0.6rad 时,网格可能移出屏幕或被建筑物遮挡;从正下方俯视会使圆柱体变成小点,失去批处理“场”的效果。-0.61rad 的俯仰角仍然足够浅,可能导致网格完全移出画面。 - 确认可见性:
primitive.ready后,如果场景只要求“批次可见”,优先使用viewer.camera.flyToBoundingSphere(primitive._boundingSpheres[0], { duration: 0 })(或viewer.flyTo(primitive)),而不是手动调整偏移量。
更新每个实例的属性
import { ColorGeometryInstanceAttribute, ShowGeometryInstanceAttribute } from "cesium";
// Wait for async geometry compilation
const removeListener = scene.postRender.addEventListener(() => {
if (!primitive.ready) return;
const attrs = primitive.getGeometryInstanceAttributes("rect");
attrs.color = ColorGeometryInstanceAttribute.toValue(Color.YELLOW);
attrs.show = ShowGeometryInstanceAttribute.toValue(true);
removeListener();
});
PrimitiveCollection
可嵌套的容器——scene.primitives 本身就是一个 PrimitiveCollection。
import { PrimitiveCollection, BillboardCollection, LabelCollection } from "cesium";
const group = new PrimitiveCollection();
group.add(new BillboardCollection());
group.add(new LabelCollection());
scene.primitives.add(group);
group.show = false; // toggle all children
选择矢量数据路径
| 需求 | 使用 |
|---|---|
| Entity 生命周期、聚类、每个 Entity 的样式设置、随时间变化的值 | cesiumjs-entities 中的 GeoJsonDataSource |
| 单个大型 GeoJSON 对象,且需要较低开销和 Primitive 级性能 | 此技能中的 GeoJsonPrimitive |
| 瓦片矢量数据、3D Tiles LOD、元数据样式设置、要素拾取 | cesiumjs-3d-tiles 中的 MVTDataProvider |
| 完全手动管理的高吞吐量点/折线/多边形缓冲区 | BufferPointCollection、BufferPolylineCollection、BufferPolygonCollection |
缓冲区基本图元集合(实验性,1.140+)
对于实体/数据源开销过高的大型矢量数据集,请使用 BufferPointCollection、BufferPolylineCollection 和 BufferPolygonCollection。这些 API 在 1.140(#13212)中引入,并在 1.142 中进一步完善;它们属于实验性功能,使用轻量对象:添加或遍历数千个项目时,应重复使用同一个 BufferPoint、BufferPolyline 或 BufferPolygon。
import {
BlendOption,
BoundingSphere,
BufferPoint,
BufferPointCollection,
BufferPointMaterial,
Cartesian3,
Color,
} from "cesium";
const positions = [
Cartesian3.fromDegrees(-75.16, 39.95),
Cartesian3.fromDegrees(-73.98, 40.75),
];
const points = scene.primitives.add(new BufferPointCollection({
primitiveCountMax: positions.length,
allowPicking: true,
blendOption: BlendOption.TRANSLUCENT,
boundingVolume: BoundingSphere.fromPoints(positions), // world space in 1.142+
}));
const point = new BufferPoint();
const material = new BufferPointMaterial({
color: Color.CYAN.withAlpha(0.65),
outlineColor: Color.WHITE.withAlpha(0.9),
outlineWidth: 2,
size: 10,
});
positions.forEach((position, featureId) => {
points.add({
position,
featureId,
material,
}, point);
});
const picked = scene.pick(windowPosition);
if (picked?.collection === points) {
console.log(picked.index, picked.primitive.featureId);
}
破坏性变更(1.141,#13448):
BufferPrimitiveCollection.modelMatrix、boundingVolume和boundingVolumeWC现在为只读属性——你可以原地修改对象,但重新赋值属性(collection.modelMatrix = ...)会抛出异常。请更新现有矩阵/包围体,而不是替换为新的对象。
1.142 说明:
boundingVolume现在采用世界坐标,而非局部/模型坐标。如果手动提供该值,需自行应用集合的modelMatrix变换。- 提供
boundingVolume后会跳过自动重新计算;这有助于处理大型动画集合,但你需要自行确保包围体保持有效。 - 三种缓冲区集合均支持
blendOption,并可启用来自BufferPrimitiveMaterial#color的 alpha;BufferPointCollection也会遵循outlineColor.alpha。 - 仅当所有材质都完全不透明时,才使用
BlendOption.OPAQUE;alpha 会变化时,请使用TRANSLUCENT或混合模式。
在 1.143 中,当 outlineWidth 为 0 时,BufferPointCollection 不再将 outlineColor 泄漏到填充区域。将宽度设为 0 即可禁用轮廓;请移除会增加批处理复杂度的透明轮廓变通方案。
GeoJsonPrimitive(实验性,1.142+)
GeoJsonPrimitive 可将 GeoJSON 直接加载到缓冲区基本图元集合中,绕过 GeoJsonDataSource 和实体层。对于大型静态矢量数据集或批量更新的矢量数据集,优先使用它。如果需要实体层的便利功能、时间动态属性、聚类或 DataSource 生命周期集成,请继续使用 GeoJsonDataSource。
import { GeoJsonPrimitive } from "cesium";
const counties = await GeoJsonPrimitive.fromUrl("/data/counties.geojson", {
allowPicking: true,
});
scene.primitives.add(counties);
console.log(counties.featureCount);
console.log(counties.points); // BufferPointCollection | undefined
console.log(counties.polylines); // BufferPolylineCollection | undefined
console.log(counties.polygons); // BufferPolygonCollection | undefined
// Picking returns the GeoJsonPrimitive pick object, including source properties.
const picked = scene.pick(windowPosition);
if (picked?.parentPrimitive === counties) {
const featureId = picked.primitive.featureId;
console.log(counties.getId(featureId));
console.log(counties.getProperties(featureId));
}
如果 GeoJSON 已在内存中,可使用 GeoJsonPrimitive.fromGeoJson(parsedObject)。源要素 ID 可通过 ids/getId() 获取,源属性可通过 properties/getProperties() 获取。
内置几何类型(31)
所有几何体都需要形状参数,以及与外观匹配的 vertexFormat。大多数几何体都有对应的 *OutlineGeometry。轮廓需要单独的 Primitive。
填充 + 轮廓模式
import {
Primitive, GeometryInstance, PolygonGeometry, PolygonOutlineGeometry,
PolygonHierarchy, PerInstanceColorAppearance, ColorGeometryInstanceAttribute,
Cartesian3, Color,
} from "cesium";
const positions = Cartesian3.fromDegreesArray([-115, 37, -115, 32, -107, 33, -102, 35]);
// Fill primitive
scene.primitives.add(new Primitive({
geometryInstances: new GeometryInstance({
geometry: new PolygonGeometry({
polygonHierarchy: new PolygonHierarchy(positions),
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.CYAN.withAlpha(0.5)) },
}),
appearance: new PerInstanceColorAppearance(),
}));
// Outline primitive (separate draw call)
scene.primitives.add(new Primitive({
geometryInstances: new GeometryInstance({
geometry: new PolygonOutlineGeometry({ polygonHierarchy: new PolygonHierarchy(positions) }),
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.WHITE) },
}),
appearance: new PerInstanceColorAppearance({ flat: true }),
}));
几何体目录
除特别注明外,每个 XxxGeometry 都有对应的 XxxOutlineGeometry。
表面(适用于 GroundPrimitive):CircleGeometry、CorridorGeometry、EllipseGeometry、PolygonGeometry、RectangleGeometry。
体积(需要 modelMatrix):BoxGeometry(fromDimensions())、CylinderGeometry(当 topRadius != bottomRadius 时为圆锥)、EllipsoidGeometry、SphereGeometry、FrustumGeometry、PlaneGeometry。
路径:CorridorGeometry(缓冲路径)、PolylineVolumeGeometry(沿路径挤出的 2D 形状)、WallGeometry(垂直帘幕)。
多边形:PolygonGeometry(通过 PolygonHierarchy 创建孔洞)、CoplanarPolygonGeometry(非地球表面)。
线(无轮廓):PolylineGeometry(像素宽度)、SimplePolylineGeometry(1px)、GroundPolylineGeometry(仅限 GroundPolylinePrimitive)。
在离地位置放置几何体
Box、Ellipsoid、Cylinder 和 Frustum 需要在 GeometryInstance 上设置 modelMatrix。
import { GeometryInstance, BoxGeometry, PerInstanceColorAppearance,
ColorGeometryInstanceAttribute, Cartesian3, Matrix4, Transforms, Color } from "cesium";
const modelMatrix = Matrix4.multiplyByTranslation(
Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-105, 40)),
new Cartesian3(0, 0, 250000), new Matrix4(),
);
new GeometryInstance({
geometry: BoxGeometry.fromDimensions({
dimensions: new Cartesian3(400000, 300000, 500000),
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
modelMatrix,
id: "floatingBox",
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.CORAL) },
});
外观(7 种)
| 外观 | 用例 | 是否需要材质? |
|---|---|---|
PerInstanceColorAppearance | 每个实例使用单独颜色 | 否 |
MaterialAppearance | 任意几何体 + 材质 | 是 |
EllipsoidSurfaceAppearance | 曲面几何体 + 材质(属性较少) | 是 |
PolylineColorAppearance | 每条实例化折线使用单独颜色 | 否 |
PolylineMaterialAppearance | 使用材质的折线 | 是 |
DebugAppearance | 可视化顶点属性 | 否 |
Appearance | 基类 / 自定义着色器 | 可选 |
几何体的 vertexFormat 必须与外观匹配。请使用外观的静态 VERTEX_FORMAT。对于不启用光照的 PerInstanceColorAppearance,请使用 FLAT_VERTEX_FORMAT。
MaterialAppearance 示例
import { Primitive, GeometryInstance, WallGeometry, MaterialAppearance, Material, Cartesian3 } from "cesium";
scene.primitives.add(new Primitive({
geometryInstances: new GeometryInstance({
geometry: new WallGeometry({
positions: Cartesian3.fromDegreesArrayHeights([-115, 44, 200000, -110, 44, 200000, -105, 44, 200000]),
vertexFormat: MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat,
}),
}),
appearance: new MaterialAppearance({
material: Material.fromType("Checkerboard"),
faceForward: true, // shade both sides
}),
}));
GroundPrimitive
将几何体贴合到地形 / 3D Tiles 上。支持:CircleGeometry、CorridorGeometry、EllipseGeometry、PolygonGeometry、RectangleGeometry。将其添加到 scene.primitives(而不是 scene.groundPrimitives——两者都可用,但使用不带 Ion 地形的公共底图时,通常使用 scene.primitives)。
import { GroundPrimitive, GeometryInstance, PolygonGeometry, PolygonHierarchy,
PerInstanceColorAppearance, ColorGeometryInstanceAttribute, ClassificationType,
Cartesian3, Color } from "cesium";
scene.primitives.add(new GroundPrimitive({
geometryInstances: new GeometryInstance({
geometry: new PolygonGeometry({
polygonHierarchy: new PolygonHierarchy(
Cartesian3.fromDegreesArray([-112, 36, -112, 36.1, -111.9, 36.1]),
),
}),
id: "groundPolygon",
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.RED.withAlpha(0.5)) },
}),
appearance: new PerInstanceColorAppearance({ flat: true, translucent: true }),
classificationType: ClassificationType.TERRAIN, // TERRAIN, CESIUM_3D_TILE, or BOTH
}));
GroundPolylinePrimitive
将折线贴合到地形上。将其添加到 scene.primitives(而不是 scene.groundPrimitives)。
import { GroundPolylinePrimitive, GeometryInstance, GroundPolylineGeometry,
PolylineColorAppearance, ColorGeometryInstanceAttribute, Cartesian3, Color } from "cesium";
scene.primitives.add(new GroundPolylinePrimitive({
geometryInstances: new GeometryInstance({
geometry: new GroundPolylineGeometry({
positions: Cartesian3.fromDegreesArray([-112.13, 36.05, -112.09, 36.10, -112.13, 36.17]),
width: 4.0,
loop: true,
}),
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.LIME.withAlpha(0.7)) },
}),
appearance: new PolylineColorAppearance(),
}));
ClassificationPrimitive
高亮用于对地形或 3D Tiles 进行分类的体积。有效类型:BoxGeometry、CylinderGeometry、EllipsoidGeometry、PolylineVolumeGeometry、SphereGeometry,以及拉伸曲面几何体。
import { ClassificationPrimitive, GeometryInstance, BoxGeometry, PerInstanceColorAppearance,
ColorGeometryInstanceAttribute, ClassificationType, Cartesian3, Transforms, Color } from "cesium";
scene.primitives.add(new ClassificationPrimitive({
geometryInstances: new GeometryInstance({
geometry: BoxGeometry.fromDimensions({
dimensions: new Cartesian3(100, 100, 50),
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.59, 40.04, 25)),
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.YELLOW.withAlpha(0.5)) },
}),
classificationType: ClassificationType.BOTH,
}));
BillboardCollection
与视口对齐的图像,GPU 效率高——大规模使用时的性能远胜实体。
破坏性变更(1.140,#13253):
BillboardCollection和LabelCollection现在需要 WebGL 2,或支持ANGLE_instanced_arrays且MAX_VERTEX_TEXTURE_IMAGE_UNITS > 0的 WebGL 1。在不支持的设备上,它们将不再 渲染——如果仍需支持旧版 WebGL 1 硬件,请通过scene.context.webgl2判断(或检测扩展)。
基本用法
兼容性修复(1.143): 应用替换全局
Promise实现后,公告牌图像加载不再崩溃。请使用带 URL、已加载图像或画布的公共image属性;对于Resource或回调,请使用setImage。不要根据原生Promise的身份进行分支,也不要为此问题保留兼容性垫片。
import { BillboardCollection, Cartesian3, Color, NearFarScalar,
HeightReference, HorizontalOrigin, VerticalOrigin } from "cesium";
const billboards = scene.primitives.add(new BillboardCollection({ scene }));
const b = billboards.add({
position: Cartesian3.fromDegrees(-75.59, 40.04),
image: "marker.png",
horizontalOrigin: HorizontalOrigin.CENTER,
verticalOrigin: VerticalOrigin.BOTTOM,
heightReference: HeightReference.CLAMP_TO_GROUND,
scaleByDistance: new NearFarScalar(1000, 1.5, 1e7, 0.3),
});
b.position = Cartesian3.fromDegrees(-75.60, 40.05); // update dynamically
billboards.remove(b);
PinBuilder——程序化图钉图像
PinBuilder 可在运行时生成基于画布的图钉图标,无需外部图像文件。使用 fromColor 创建纯色图钉,或使用 fromText 创建带标签的图钉。将返回的画布作为公告牌的 image 传入。
如果场景指定了城市 / 项目的有序列表和按索引着色的方案,请按给定顺序遍历源数组,并直接将循环索引用作 HSL 色相索引。重新排列源列表(例如按纬度排序)会导致城市与颜色的对应关系发生变化,无法通过视觉检查。
import { BillboardCollection, PinBuilder, Cartesian3, Color, VerticalOrigin } from "cesium";
const pinBuilder = new PinBuilder();
const cities = [
{ name: "Boston", lng: -71.0589, lat: 42.3601 },
{ name: "New York", lng: -74.0060, lat: 40.7128 },
{ name: "Philadelphia", lng: -75.1652, lat: 39.9526 },
{ name: "Washington DC",lng: -77.0369, lat: 38.9072 },
{ name: "Miami", lng: -80.1918, lat: 25.7617 },
];
const billboards = scene.primitives.add(new BillboardCollection({ scene }));
cities.forEach((city, index) => {
billboards.add({
position: Cartesian3.fromDegrees(city.lng, city.lat),
// Color.fromHsl(hue 0-1, saturation, lightness) produces evenly-spaced hues
image: pinBuilder.fromColor(Color.fromHsl(index / cities.length, 0.8, 0.5), 48),
verticalOrigin: VerticalOrigin.BOTTOM,
});
});
// Text label pin: pinBuilder.fromText("A", Color.ROYALBLUE, 48)
// fromColor / fromText return a canvas -- pass directly as image
Color.fromHsl(hue, saturation, lightness)——通过改变 hue(0–1,循环覆盖完整色环)生成光谱中的颜色。适用于为 N 个项目生成彩虹色:Color.fromHsl(i / n, 0.8, 0.5)。Color.fromRandom({ alpha })——随机生成色相 / 饱和度 / 亮度,并固定透明度。
LabelCollection
import { LabelCollection, Cartesian3, Cartesian2, Color, LabelStyle, VerticalOrigin } from "cesium";
const labels = scene.primitives.add(new LabelCollection({ scene }));
labels.add({
position: Cartesian3.fromDegrees(-75.59, 40.04, 300),
text: "Philadelphia",
font: "16px sans-serif",
fillColor: Color.WHITE,
outlineColor: Color.BLACK,
outlineWidth: 2,
style: LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: VerticalOrigin.BOTTOM,
pixelOffset: new Cartesian2(0, -10),
});
PointPrimitiveCollection
import { PointPrimitiveCollection, Cartesian3, Color, NearFarScalar } from "cesium";
const points = scene.primitives.add(new PointPrimitiveCollection());
points.add({
position: Cartesian3.fromDegrees(-75.59, 40.04),
pixelSize: 10,
color: Color.YELLOW,
outlineColor: Color.BLACK,
outlineWidth: 2,
scaleByDistance: new NearFarScalar(1000, 1.0, 1e7, 0.1),
});
CloudCollection 和 PolylineCollection
import { CloudCollection, PolylineCollection, Cartesian3, Cartesian2, Color, Material } from "cesium";
// Procedural cumulus clouds
const clouds = scene.primitives.add(new CloudCollection());
clouds.add({
position: Cartesian3.fromDegrees(-75.59, 40.04, 1500),
scale: new Cartesian2(40, 12),
maximumSize: new Cartesian3(40, 12, 15),
slice: 0.36,
});
// Low-level polyline collection
const polylines = scene.primitives.add(new PolylineCollection());
polylines.add({
positions: Cartesian3.fromDegreesArray([-75, 40, -70, 42, -65, 38]),
width: 3.0,
material: Material.fromType("Color", { color: Color.AQUA }),
});
通过 Primitive 绘制折线
import { Primitive, GeometryInstance, PolylineGeometry, PolylineColorAppearance,
ColorGeometryInstanceAttribute, Cartesian3, Color, ArcType } from "cesium";
scene.primitives.add(new Primitive({
geometryInstances: new GeometryInstance({
geometry: new PolylineGeometry({
positions: Cartesian3.fromDegreesArray([0, 0, 5, 0]),
width: 10.0,
vertexFormat: PolylineColorAppearance.VERTEX_FORMAT,
arcType: ArcType.GEODESIC, // GEODESIC, RHUMB, or NONE
}),
attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.WHITE) },
}),
appearance: new PolylineColorAppearance({ translucent: false }),
}));
枚举
| 枚举 | 值 | 用于 |
|---|---|---|
ArcType | GEODESIC、RHUMB、NONE | PolylineGeometry、PolygonGeometry |
CornerType | ROUNDED、MITERED、BEVELED | CorridorGeometry、PolylineVolumeGeometry |
ClassificationType | TERRAIN、CESIUM_3D_TILE、BOTH | GroundPrimitive、ClassificationPrimitive |
PrimitiveType | POINTS、LINES、TRIANGLES 等 | 底层 Geometry |
CloudType | CUMULUS | CloudCollection |
基元场景的相机取景
程序化检查(基元数量、相机位置)可能通过,但视觉输出却完全没有呈现出几何体。视觉评估中反复出现的一些经验法则:
- 体积几何网格(圆柱体/立方体): 使用约
-PI/4(约-0.785弧度,-45°)的俯仰角,距离约为3 * gridFootprint。俯仰角浅于约-0.6弧度时,网格可能落在相机后方或画面之外;俯仰角接近-PI/2时,垂直范围会被压扁,整批对象看起来像点。 - 铺设在地形上的表面多边形(GroundPrimitive): 俯仰角较陡(约
-50°)且距离较远时,多边形会缩成画面底部边缘的一条细带。缩短距离或采用更平缓的俯仰角,让多边形位于画面中央。 - 大陆级折线(66 号公路、跨洲路线): 从质心上方约 5–6 Mm 处以接近天底的俯视角观察,可让整条路径保持可见。
- 沿海岸/路线排列的标记链: 将相机对准标记链的中点,并设置足以在四周留出余量、涵盖标记链包围盒的距离。
如有疑问,在 primitive.ready 后调用 viewer.flyTo(primitive) 或 viewer.camera.flyToBoundingSphere(primitive._boundingSpheres[0]),即可自动为整批对象取景。
性能提示
- 尽可能批处理。 将数千个 GeometryInstances 合并到一个 Primitive 中,以实现一次绘制调用。
- 每个实例只需不同颜色时,使用
PerInstanceColorAppearance。 - 无需光照时,在 PerInstanceColorAppearance 上设置
flat: true;这会使用FLAT_VERTEX_FORMAT。 - 对于永远不会被选取的 Primitive,设置
allowPicking: false以节省 GPU 内存。 - 保持
asynchronous: true(默认值)。 访问实例属性前,检查primitive.ready。 - Billboard、Label 和 PointPrimitive 尽量使用较少的大型集合。 按更新频率分组。
- 所有项目均为不透明时,在 BillboardCollection/PointPrimitiveCollection 上使用
BlendOption.OPAQUE(最高可提升 2 倍)。 - 对于大型矢量数据,如果可以接受轻量级更新,请使用缓冲区基元集合。
- 对于大型动画集合,预先计算缓冲区集合的包围体积;但请记住,在 1.142+ 中它们采用世界坐标。
- 地形贴合使用 GroundPrimitive,而不是实体的
heightReference。 - 将填充和轮廓拆分为两个 Primitive——它们无法共用一次绘制调用。
- 让
vertexFormat与外观完全匹配,以跳过未使用的顶点属性计算。 - 表面几何使用
EllipsoidSurfaceAppearance,而不是MaterialAppearance——前者所需的顶点属性更少。
另请参阅
- cesiumjs-entities -- 高级 Entity API,封装了带有时间动态属性的基元。
- cesiumjs-3d-tiles -- 使用
MVTDataProvider将分块矢量数据作为运行时 3D Tiles。 - cesiumjs-materials-shaders -- 外观和后期处理所使用的 Material(Fabric)系统。
- cesiumjs-spatial-math -- 用于几何体定位的 Cartesian3、Matrix4、Transforms 和坐标转换。