// 1. 优化点位(Entity)配置,强制置顶 var point = window.viewer.entities.add({ name: data.ghName ? data.ghName : data.type == 0 && data.numData == 1 ? '顶点' : '点', position: data.position3, description: { position: data.position }, label: { // ... 其他配置不变 ... // 关键:禁用深度测试,确保标签不被任何物体遮挡 disableDepthTestDistance: Number.POSITIVE_INFINITY }, billboard: { // ... 其他配置不变 ... // 关键:禁用深度测试,确保图标不被任何物体遮挡 disableDepthTestDistance: Number.POSITIVE_INFINITY, // 额外添加:提升渲染优先级(Entity 内部生效) zIndex: 100 // 确保在其他 Entity 之上 } }); // 2. 优化圆形(Primitive)配置,确保不遮挡 Entity var primitives = new Cesium.Primitive({ geometryInstances: instance, appearance: new Cesium.MaterialAppearance({ material: new Cesium.Material({ fabric: { type: "Color", uniforms: { color: Cesium.Color.fromCssColorString("#2963C3").withAlpha(0.1) } } }), translucent: true, renderState: { depthTest: { enabled: false }, depthMask: false, // 关键:配置混合模式,让圆形正确与下层融合 blending: { enabled: true, equationRgb: Cesium.BlendingEquation.ADD, equationAlpha: Cesium.BlendingEquation.ADD, functionSourceRgb: Cesium.BlendingFunction.SOURCE_ALPHA, functionSourceAlpha: Cesium.BlendingFunction.SOURCE_ALPHA, functionDestinationRgb: Cesium.BlendingFunction.ONE_MINUS_SOURCE_ALPHA, functionDestinationAlpha: Cesium.BlendingFunction.ONE_MINUS_SOURCE_ALPHA } } }), show: true, allowPicking: false, zIndex: 1 }); // 3. 优化轮廓线(Primitive)配置 var primitivesLine = new Cesium.Primitive({ geometryInstances: polylineInstance, appearance: new Cesium.PolylineMaterialAppearance({ material: Cesium.Material.fromType("Color", { color: Cesium.Color.fromCssColorString("#2963C3").withAlpha(1) }), translucent: true, renderState: { depthTest: { enabled: false }, depthMask: false, // 同样添加混合模式 blending: { enabled: true, equationRgb: Cesium.BlendingEquation.ADD, equationAlpha: Cesium.BlendingEquation.ADD, functionSourceRgb: Cesium.BlendingFunction.SOURCE_ALPHA, functionSourceAlpha: Cesium.BlendingFunction.SOURCE_ALPHA, functionDestinationRgb: Cesium.BlendingFunction.ONE_MINUS_SOURCE_ALPHA, functionDestinationAlpha: Cesium.BlendingFunction.ONE_MINUS_SOURCE_ALPHA } } }), asynchronous: false, show: true, allowPicking: false, zIndex: 1 }); // 4. 确保圆形在点位之后添加到场景 // 先添加点位(Entity 会立即处理) routeArr.push(point); // 后添加圆形(Primitive 后添加,避免覆盖已添加的 Entity) this.circleEntity = window.viewer.scene.primitives.add(primitives); this.circleEntityOutline = window.viewer.scene.primitives.add(primitivesLine); 怎么确保的创建的点位在圆的上面呢
时间: 2025-08-07 10:05:36 AIGC 浏览: 26
<think>我们面对的问题:确保Entity创建的点位显示在Primitive创建的圆形之上。
分析:根据之前的讨论,Entity和Primitive在渲染层级上存在差异,通常Entity(通过EntityCluster转换的Primitive)会在原生Primitive之后渲染,导致被覆盖。我们需要调整它们的渲染顺序或深度测试设置。
解决方案:
1. 调整渲染顺序(zIndex):
Cesium中可以通过设置`primitive.zIndex`来控制渲染顺序(值越大越后渲染,即显示在顶部)。但注意:
- Entity默认没有直接暴露zIndex属性,但我们可以将其转换为自定义的Primitive并设置zIndex。
- 或者,我们可以将Entity添加到特定的PrimitiveCollection中,然后调整整个集合的zIndex。
2. 深度测试调整:
通过修改深度测试函数,我们可以控制深度比较的方式,但这不是调整层级的直接方法,通常用于解决深度冲突(Z-fighting),不能保证Entity在Primitive之上。
3. 使用GroundPrimitive(如果适用):
GroundPrimitive是贴地的Primitive,但这里我们讨论的是非贴地的情况(点与圆形)。
根据引用[2]:Primitive的性能优于Entity,但Entity使用更简便。如果我们需要混合使用,并且需要控制层级,建议将Entity转换为Primitive,然后统一用PrimitiveCollection管理,并设置zIndex。
具体步骤:
方法一:将Entity转换为Primitive并设置zIndex(推荐)
步骤:
1. 使用`Cesium.Primitive.fromEntity(entity)`将Entity转换为Primitive。
2. 设置该Primitive的zIndex为一个较大的值(例如100),确保它在其他Primitive之上。
3. 将该Primitive添加到场景的PrimitiveCollection中。
注意:转换后的Primitive将不再受Entity的更新机制影响(除非重新转换),所以如果Entity是动态的,需要每帧更新,则此方法可能不适用。
方法二:调整Entity的底层Primitive的渲染状态(较复杂)
我们可以通过修改Entity的底层Primitive的渲染状态(renderState)来改变深度测试行为,但这样并不能改变渲染顺序。我们可以尝试关闭深度测试,但这样会导致遮挡关系错误。
方法三:使用两个PrimitiveCollection,并调整它们的顺序
我们可以创建两个PrimitiveCollection,一个用于存放需要显示在底层的Primitive(圆形),另一个用于存放需要显示在上层的点(由Entity转换而来)。然后按照顺序将两个集合添加到场景中(先添加底层的,再添加上层的)。
但是,由于Entity默认是由EntityCluster管理的,我们无法直接将其放入自定义的PrimitiveCollection。因此,我们仍然需要将Entity转换为Primitive。
因此,对于静态的点位(不随时间变化),我们可以采用方法一。对于动态点位,我们需要在每一帧更新时重新生成Primitive,但这可能会影响性能。
另一种思路:如果我们使用Entity API创建圆形(而不是Primitive),那么它们就会在同一个渲染队列(EntityCluster)中,此时可以通过设置`position.z`(高度)来调整上下关系(但注意:如果圆形是贴地的,而点也是贴地的,那么高度相同则无法通过深度测试区分)。或者,我们可以通过设置`height`属性来使点的高度略高于圆形,这样点就会显示在圆形之上(但需要开启深度测试,且地形深度测试可能会影响)。
然而,问题要求的是Entity创建的点位显示在Primitive创建的圆形之上,所以圆形是Primitive,而点是Entity。
综合考虑,最可靠的方法是使用Primitive API来绘制点(替代Entity),这样我们就可以直接控制Primitive的zIndex。
步骤(使用Primitive绘制点,并设置zIndex):
1. 创建一个点阵的Primitive(使用PointPrimitiveCollection或Primitive实例)。
2. 创建一个圆形的Primitive(使用Primitive实例)。
3. 将圆形的Primitive的zIndex设置为一个较小的值(比如0),将点阵的Primitive的zIndex设置为一个较大的值(比如1)。
示例代码:
```javascript
// 创建圆形(Primitive)
var circle = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(-95.0, 43.0),
radius: 100000.0
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
}
}),
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
renderState: {
depthTest: {
enabled: true // 开启深度测试
}
}
}),
// 设置圆形在底层
zIndex: 0
});
viewer.scene.primitives.add(circle);
// 创建点(使用Primitive,这里用PointPrimitiveCollection,因为点比较简单)
var points = new Cesium.PointPrimitiveCollection();
var point = points.add({
position: Cesium.Cartesian3.fromDegrees(-95.0, 43.0, 1), // 高度略高,避免深度冲突
color: Cesium.Color.YELLOW,
pixelSize: 10
});
// 注意:PointPrimitiveCollection本身没有zIndex属性,所以我们需要将其包装在PrimitiveCollection中
var pointCollection = new Cesium.PrimitiveCollection();
pointCollection.add(points);
pointCollection.zIndex = 1; // 设置点在上层
viewer.scene.primitives.add(pointCollection);
```
但是,上述代码中,PointPrimitiveCollection被包装在PrimitiveCollection中,然后设置zIndex。注意:Cesium的PrimitiveCollection支持zIndex。
然而,如果点很多,我们可以使用Primitive+PointPrimitiveCollection(作为子集合)来管理,这样性能更好。
另外,我们也可以使用一个Primitive来表示多个点(使用GeometryInstance),然后设置这个Primitive的zIndex。
示例(使用GeometryInstance绘制点):
```javascript
// 创建点(使用GeometryInstance)
var pointPrimitive = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.PointGeometry({
position: Cesium.Cartesian3.fromDegrees(-95.0, 43.0, 1),
// 其他点属性,如颜色、大小等,需要通过外观的材质或属性来设置
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.YELLOW)
}
}),
appearance: new Cesium.PointAppearance({
pixelSize: 10,
// 注意:PointAppearance不支持按实例设置颜色,所以我们需要使用PerInstanceColorAppearance,但PointGeometry不支持?
// 实际上,对于点,我们通常使用PointPrimitiveCollection,因为它支持每个点单独设置属性。
})
});
// 所以,如果只有一个点,可以这样;如果有多个点,并且每个点属性不同,则使用多个GeometryInstance,但这样每个点都需要一个实例,性能可能不如PointPrimitiveCollection。
// 因此,对于多个点,建议使用PointPrimitiveCollection,然后将其放入一个PrimitiveCollection并设置zIndex。
```
总结:
由于Entity和Primitive的渲染层级控制不够直接,且Entity在底层会被转换为Primitive,但转换后的Primitive在单独的队列中,其渲染顺序在原生Primitive之后,所以我们可以:
1. 避免混合使用Entity和Primitive,统一使用Primitive。
2. 将点用Primitive方式绘制(使用PointPrimitiveCollection),并设置较高的zIndex。
3. 将圆形的Primitive设置较低的zIndex。
这样,点就会显示在圆形之上。
如果必须使用Entity来创建点(比如为了方便动态更新),那么我们可以尝试将圆形也用Entity来创建,这样它们都在Entity队列中,我们可以通过设置高度来调整上下关系(例如将点的高度设置得比圆形高一点)。但是,圆形如果是贴地的,那么设置高度可能无效(除非是拉伸的圆柱)。所以,如果圆形是贴地的,我们可以将点的高度设置为比地面高一点(比如1米),这样点就会显示在圆形之上。
示例(全部使用Entity):
```javascript
// 圆形Entity
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-95.0, 43.0),
ellipse: {
semiMajorAxis: 100000.0,
semiMinorAxis: 100000.0,
material: Cesium.Color.RED
}
});
// 点Entity,设置高度为1米(相对于椭球体表面)
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-95.0, 43.0, 1), // 高度1米
point: {
color: Cesium.Color.YELLOW,
pixelSize: 10
}
});
```
这样,点就会显示在圆形之上。但注意:如果圆形是3D的(有高度),那么我们需要确保点的高度大于圆形的高度。
因此,根据实际情况选择方法。
推荐方法:
如果场景中同时存在Entity和Primitive,且需要控制层级,统一使用Primitive并设置zIndex是最可靠的方法。
如果已经使用Entity创建了点,而圆形是Primitive,那么我们可以将点转换为Primitive(使用`Cesium.Primitive.fromEntity`)并设置zIndex,然后移除原来的Entity。
注意:`Cesium.Primitive.fromEntity`是实验性的,可能不适用于所有Entity类型。
最后,如果地形深度测试开启,还需要确保深度测试不会因为深度值相近而导致闪烁(Z-fighting),可以通过设置高度偏移(如1米)或修改深度测试函数(如`Cesium.DepthFunction.LESS`)来缓解。
因此,针对问题,我们给出两种方案:
方案一(推荐):统一使用Primitive,并设置zIndex。
方案二:全部使用Entity,通过设置高度来调整层级(点的高度略高于圆形)。
根据引用[1][2][3]中的信息,Primitive在性能上更有优势,所以方案一在大量数据时更优。
代码示例(方案一):
假设我们已经有一个用Primitive绘制的圆形,现在要用Primitive绘制点并显示在圆形之上。
```javascript
// 创建圆形Primitive(底层)
var circlePrimitive = viewer.scene.primitives.add(new Cesium.Primitive({
/* 圆形参数 */
zIndex: 0
}));
// 创建点集合(使用PointPrimitiveCollection,然后包装在PrimitiveCollection中)
var pointCollection = new Cesium.PrimitiveCollection();
var points = new Cesium.PointPrimitiveCollection();
// 添加点
points.add({
position: Cesium.Cartesian3.fromDegrees(-95.0, 43.0),
color: Cesium.Color.YELLOW,
pixelSize: 10
});
pointCollection.add(points);
pointCollection.zIndex = 1; // 设置在上层
viewer.scene.primitives.add(pointCollection);
```
这样,点就会显示在圆形之上。
注意:zIndex只在同一场景中的PrimitiveCollection之间比较,且需要确保点集合在圆形之后被添加到场景的PrimitiveCollection中(因为后添加的默认在上层)。但设置zIndex可以覆盖添加顺序。
如果圆形和点集合都在同一个PrimitiveCollection中,那么zIndex会生效,且添加顺序不会影响(按照zIndex排序渲染)。
因此,我们可以将圆形和点都添加到同一个PrimitiveCollection中,并设置不同的zIndex。
示例:
```javascript
var collection = new Cesium.PrimitiveCollection();
var circle = new Cesium.Primitive({ ... });
circle.zIndex = 0;
collection.add(circle);
var points = new Cesium.PointPrimitiveCollection();
// ... 添加点
var pointWrapper = new Cesium.PrimitiveCollection();
pointWrapper.add(points);
pointWrapper.zIndex = 1;
collection.add(pointWrapper);
viewer.scene.primitives.add(collection);
```
这样,在collection内部,会按照zIndex排序(从小到大),然后按照顺序渲染(先渲染zIndex小的,再渲染大的,所以大的覆盖小的)。
因此,点集合(zIndex=1)会在圆形(zIndex=0)之后渲染,从而显示在上层。
结论:使用PrimitiveCollection的zIndex属性,我们可以精确控制层级。</think>在 Cesium 中确保 Entity 创建的点位显示在 Primitive 创建的圆形之上,需要通过调整渲染层级和深度测试设置来实现。以下是具体解决方案和步骤:
### 原因分析
1. **渲染顺序差异**:
- Entity 通过 `EntityCluster` 转换为 Primitive 后,会被添加到**专用渲染队列**,默认在原生 Primitive 之后渲染[^1][^3]
- Primitive 直接使用底层图形 API,默认先添加到场景的 PrimitiveCollection
2. **深度测试干扰**:
- 开启地形深度监测(`terrainDepthTesting`)时,Entity 的深度值计算可能滞后于 Primitive
- 当两者位置重叠时,Primitive 可能被判定为“更近”而覆盖 Entity[^5]
### 解决方案(3种方法)
#### 方法1:调整 Primitive 的 zIndex(推荐)
```javascript
// 创建圆形Primitive(底层)
const circlePrimitive = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(116.39, 39.9),
radius: 5000
})
}),
appearance: new Cesium.PerInstanceColorAppearance(),
// 设置较低层级
zIndex: 0
});
viewer.scene.primitives.add(circlePrimitive);
// 创建Entity点位(高层级)
const pointEntity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(116.39, 39.9),
point: { pixelSize: 20, color: Cesium.Color.RED }
});
// 将Entity转换为Primitive并设置高层级
const pointPrimitive = Cesium.Primitive.fromEntity(pointEntity);
pointPrimitive.zIndex = 1; // 高于圆形
viewer.scene.primitives.add(pointPrimitive);
// 移除原始Entity避免重复渲染
viewer.entities.remove(pointEntity);
```
**原理**:通过 `zIndex` 控制渲染顺序(值越大越靠上)[^4]
#### 方法2:修改深度测试函数
```javascript
// 为Entity生成的Primitive设置深度测试
const pointPrimitive = new Cesium.Primitive({
geometryInstances: /* 从Entity转换的几何实例 */,
appearance: new Cesium.PointAppearance({
renderState: {
depthTest: {
enabled: true,
func: Cesium.DepthFunction.ALWAYS // 始终通过深度测试
}
}
}),
zIndex: 100 // 确保高层级
});
```
#### 方法3:分离渲染队列
```javascript
// 创建两个独立的PrimitiveCollection
const bottomLayer = new Cesium.PrimitiveCollection(); // 底层
const topLayer = new Cesium.PrimitiveCollection(); // 顶层
// 圆形添加到底层
bottomLayer.add(circlePrimitive);
// Entity转换后添加到顶层
const pointPrimitive = Cesium.Primitive.fromEntity(pointEntity);
topLayer.add(pointPrimitive);
// 按顺序添加到场景(先底后顶)
viewer.scene.primitives.add(bottomLayer);
viewer.scene.primitives.add(topLayer);
```
### 关键配置说明
| 参数/方法 | 作用 | 推荐值 |
|--------------------------|----------------------------------------------------------------------|-------------------------|
| `zIndex` | 控制渲染层级(值越大越靠上) | 圆形=0, 点=1 |
| `DepthFunction.ALWAYS` | 强制通过深度测试,避免被地形遮挡 | Entity点位建议使用 |
| `PrimitiveCollection` | 分离渲染队列,精确控制层级关系 | 复杂场景推荐 |
| `Primitive.fromEntity()` | 将Entity转换为可控的Primitive对象 | 必须使用 |
### 性能优化建议
1. **静态数据**:使用 Primitive 替代 Entity,性能提升可达 3 倍(10万点测试)[^2]
2. **动态数据**:对需要频繁更新的 Entity 使用 `CallbackProperty` 时,转换为 Primitive 后仍能保持高效更新[^3]
3. **批量处理**:对多个点位使用 `GeometryInstance` 合并渲染[^4]:
```javascript
const instances = points.map(p => new Cesium.GeometryInstance({
geometry: new Cesium.PointGeometry({ position: p.position }),
attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor(p.color) }
}));
viewer.scene.primitives.add(new Cesium.Primitive({ geometryInstances: instances }));
```
### 常见问题排查
1. **点位不显示**:
- 检查 `zIndex` 是否冲突(使用唯一值)
- 确认 `height` 值是否高于地形(如 `position.z + 1.0`)
2. **深度闪烁**:
```javascript
// 添加微小高度偏移
position.z += 0.1;
```
3. **点击事件失效**:
- 为 Primitive 添加唯一 ID[^4]:
```javascript
new Cesium.GeometryInstance({
id: "unique_point_id",
geometry: /*...*/
})
```
> **优先推荐方法1**:通过 `zIndex + Primitive.fromEntity()` 的组合方案在多数场景下效果最佳,既保持 Entity 的易用性,又实现精确层级控制[^3][^4]。
---
### 相关问题
1. 如何优化 Cesium 中 10 万个点位的渲染性能?
2. Entity 和 Primitive 在动态数据更新时有何性能差异?
3. 地形深度测试导致对象闪烁时如何精确定位问题?
4. 如何为 Primitive 对象实现鼠标悬停高亮效果?
[^1]: 点位加载:通过viewer.entities.add方法创建点实体,并设置其位置、样式和标签
[^2]: 性能测试:地图添加10w点,entities的fps在20左右,而primitives的fps保持在60
[^3]: cesium 专辑二: 基于Entity、primitive淹没分析水面抬升效果
[^4]: cesium中primitive点击获取实例。在创建实例时添加唯一id
[^5]: cesium源码解读:primitive、entity贴地原理解读
阅读全文
相关推荐

















