cesium primitive 和 entity 开启了地形深度监测,为什么 entity 在 primitive的下面
时间: 2025-08-07 08:05:39 AIGC 浏览: 41
<think>我们正在处理用户关于Cesium中Primitive和Entity在开启地形深度监测时的渲染层级关系的问题。用户的问题是:为什么开启地形深度监测时,Entity渲染在Primitive的下面?
根据提供的引用材料,我们可以总结如下:
1. Entity API是在Primitive API基础上封装的高级API,更易于使用,但底层仍然使用Primitive(引用[1][2][3])。
2. Primitive API是底层图形API,直接控制图形绘制,效率高,但使用复杂(引用[2][3])。
3. 当添加Entity时,Cesium会在底层创建对应的Primitive对象(引用[1])。
关于地形深度监测(terrain depth testing),这是Cesium中用于使物体与地形表面正确融合的技术。开启地形深度监测后,物体会根据地形深度进行深度测试,从而正确地显示在地形之上或之下。
现在,回答用户的问题:为什么开启地形深度监测时,Entity渲染在Primitive的下面?
原因可能涉及Cesium的渲染顺序和深度测试机制。在Cesium中,渲染顺序通常由多个因素决定,包括:
- 渲染通道(例如,不透明物体、半透明物体)
- 与相机的距离(用于排序半透明物体)
- 以及显式的渲染顺序设置
根据Cesium的渲染流程,地形本身是一个复杂的几何体,而Primitive和Entity最终都会被转换为Primitive(或PrimitiveCollection)进行渲染。
在开启地形深度监测后,Cesium会为地形生成深度纹理(depth texture),然后其他需要与地形进行深度测试的物体(如Primitive和Entity)将使用这个深度纹理进行深度测试。
然而,Entity和Primitive在添加到场景中时,它们的渲染顺序可能不同。默认情况下,Entity的渲染顺序可能被设置为在地形之后渲染,而Primitive则可能被设置为在地形之前渲染(或者反过来)。具体来说:
- Entity通常被设计为与地形交互,因此默认情况下,Entity的图形(如点、线、面)会开启深度测试,并且可能被设置为在场景中的地形之后渲染,这样它们就可以正确地与地形表面融合,即Entity会在地形之上(如果Entity的图形高度高于地形)或之下(如果低于地形)显示。
- 但是,用户观察到的现象是Entity渲染在Primitive的下面(即被Primitive遮挡),这通常是因为Primitive的渲染顺序设置在了Entity之前(即更早渲染),而Entity的渲染顺序设置在了后面(较晚渲染),同时开启了深度测试和深度写入,导致后渲染的Entity如果与Primitive有重叠,且深度值在Primitive之后,则会被遮挡。
另一种可能的解释是:Primitive在创建时,其深度测试和深度写入的设置可能与Entity不同。例如,Primitive可能默认关闭了深度写入(但开启了深度测试),这样它不会遮挡后面的物体,而Entity则可能默认开启了深度写入,导致在渲染顺序上,如果先渲染Primitive再渲染Entity,那么Entity会覆盖Primitive;反之,如果先渲染Entity再渲染Primitive,则Primitive会覆盖Entity。
但是,根据用户描述,开启地形深度监测时,Entity在Primitive下面(即被Primitive遮挡),说明在渲染顺序上,Primitive在Entity之后渲染,并且Primitive的深度值更靠近相机(即位于Entity之上)。
然而,在Cesium中,渲染顺序并不是简单的按照添加顺序,而是由多个因素决定,包括:
- 是否属于透明物体(半透明物体通常按从远到近的顺序渲染)
- 显式设置的渲染顺序(例如,通过`primitive.depthFailAppearance`或`primitive.appearance`中的`renderState`设置深度测试和深度写入,以及通过`primitive.zIndex`设置顺序)
值得注意的是,Entity在底层转换为Primitive时,可能会被添加到不同的PrimitiveCollection中。Cesium的渲染器会按照特定的顺序遍历这些集合。例如,地形本身在一个集合,而其他Primitive可能在另一个集合。Entity生成的Primitive通常被添加到`scene.primitives`集合中,而用户直接创建的Primitive也可能被添加到同一个集合或不同的集合(如`groundPrimitives`)。
在默认情况下,`scene.primitives`集合中的对象按照添加顺序渲染(除非设置了排序标志)。因此,如果先添加Entity(生成的Primitive),后添加用户创建的Primitive,那么用户创建的Primitive将在Entity之上渲染(因为后添加的Primitive默认在集合的后面,而集合的渲染顺序是从前往后,即先添加的先渲染,后添加的后渲染,后渲染的会覆盖先渲染的,如果深度测试通过)。
但是,用户观察到的是Entity在Primitive下面,也就是说Entity被Primitive遮挡。这可能是由于以下原因之一:
1. 渲染顺序:用户先添加了Primitive,然后添加了Entity,这样Entity(后添加)会渲染在Primitive(先添加)的上面(因为后添加的Primitive在集合中排在后面,后渲染)。但是,如果开启了深度测试,那么渲染顺序就不只是由添加顺序决定,还要看深度值。如果Primitive的深度值更小(离相机更近),那么即使先渲染Primitive,后渲染Entity,Entity也会因为深度测试失败(被Primitive遮挡)而不被绘制。因此,遮挡关系主要由深度值决定,而不仅仅是渲染顺序。
2. 深度测试设置:Entity生成的Primitive可能开启了深度测试,而用户创建的Primitive可能没有开启深度测试,或者深度测试设置不同(例如,深度测试函数不同),导致渲染结果不同。
3. 地形深度监测的影响:开启地形深度监测后,所有物体不仅要与地形深度进行比较,还要与其他物体的深度进行比较。如果Entity的位置高度低于Primitive的位置高度,那么Entity就会在Primitive的下面(被遮挡)。但用户的问题中并没有明确两者在高度上的差异,所以假设它们在相同位置。
因此,我们需要更具体地分析开启地形深度监测时Cesium的渲染流程:
- 地形深度监测开启后,Cesium会先渲染地形到深度纹理(深度预渲染阶段)。
- 然后,在渲染其他物体(如Primitive和Entity)时,会使用这个深度纹理进行深度测试(即与地形深度进行比较),同时也会进行物体之间的深度测试(通过深度缓冲区)。
在物体之间的深度测试中,深度值由物体在场景中的位置决定。所以,如果Primitive和Entity在同一位置,那么它们的深度值相同,此时渲染顺序就很重要:后渲染的会覆盖先渲染的(如果深度测试函数是LEQUAL,则相同深度时,后渲染的通过测试并覆盖)。
但是,用户观察到Entity在Primitive下面,说明Entity被先渲染,然后Primitive被后渲染并且覆盖了Entity。这可能是由于:
- 用户先添加了Entity(生成的Primitive),后添加了Primitive(用户创建的Primitive),所以Entity先渲染,Primitive后渲染,并且覆盖了Entity。
然而,用户的问题中描述的是“Entity渲染在Primitive的下面”,这与上述解释一致:先添加的Entity(先渲染)被后添加的Primitive(后渲染)覆盖。
但是,为什么用户会特别提到“开启地形深度监测时”?可能是因为在没有开启地形深度监测时,所有物体都不与地形进行深度测试,而物体之间的深度测试仍然存在。但是,开启地形深度监测后,由于地形深度纹理的影响,可能会导致物体在与地形深度比较时被地形遮挡,而物体之间的遮挡关系并没有改变。所以,用户观察到的现象可能不是因为地形深度监测直接导致的,而是由于物体之间的深度测试和渲染顺序。
然而,根据Cesium的官方文档和源码,Entity和Primitive在开启地形深度监测时,它们的深度测试设置可能不同。特别是,Entity生成的Primitive在创建时可能会根据Entity的属性设置深度测试相关参数(如`depthTest`和`depthFail`等)。例如,Entity的线(如折线)可能会开启`depthFail`(深度测试失败时应用的外观),这样当线在地形下面时,会以不同的样式显示(如虚线)。
因此,可能的原因是在开启地形深度监测后,Entity生成的Primitive被设置为深度测试失败时使用特殊外观(即在地形以下的部分),而用户创建的Primitive可能没有设置,导致它始终显示在Entity之上(无论地形如何)。但这并不能直接解释为什么Entity在Primitive的下面(遮挡关系)。
另一种可能是,在开启地形深度监测后,Cesium调整了渲染顺序,将地形相关的Primitive(包括Entity生成的Primitive)放在地形深度测试的特定阶段,而用户创建的Primitive则被放在另一个阶段渲染。具体来说:
- Cesium在渲染时,首先渲染不透明物体(包括地形),然后渲染半透明物体(按从远到近排序)。
- 对于需要地形深度测试的物体(如Entity),Cesium可能会将它们分为两类:一类是贴在地面上的(如点、线、面),另一类是浮在空中的(如广告牌、3D模型)。贴在地面上的物体会在渲染地形之后立即渲染,而浮在空中的物体则可能在地形渲染之后的其他阶段渲染。
但是,用户创建的Primitive可能被归类为不透明物体(如果它的外观是不透明的),而Entity生成的Primitive可能被归类为半透明物体(如果Entity设置了透明度),这样就会导致渲染顺序不同:不透明物体先渲染(包括地形和用户创建的Primitive),然后半透明物体(Entity)后渲染,并且半透明物体只能在不透明物体的缝隙中显示(即被不透明物体遮挡的部分将不可见)。
综上所述,根本原因可能是:
1. 用户创建的Primitive和Entity生成的Primitive在渲染顺序上不同(由于它们被添加到不同的集合,或者具有不同的渲染状态)。
2. 开启地形深度监测后,Entity生成的Primitive可能会被调整到特定的渲染阶段(如地形深度测试阶段),而用户创建的Primitive则可能被视为普通物体,在另一个阶段渲染,导致覆盖关系变化。
具体到Cesium源码,我们可以参考以下流程:
- 在`Scene.js`的`render`函数中,渲染顺序大致如下:
a. 天空盒、星空
b. 太阳、月亮
c. 不透明物体(包括地形、3D Tiles等)
d. 半透明物体(按距离排序)
Entity生成的Primitive(通过`PrimitiveCollection`)通常被添加到`scene.primitives`中,而地形则有自己的`globe`对象。在渲染不透明物体时,会先渲染地形,然后渲染`scene.primitives`中的不透明物体(按添加顺序),然后渲染半透明物体(按从远到近)。
如果用户创建的Primitive是不透明的,而Entity生成的Primitive是半透明的(比如设置了透明度),那么用户创建的Primitive会在半透明物体之前渲染,因此它可能会遮挡后面渲染的半透明Entity。
因此,如果用户看到的Entity是半透明的(或者部分透明),那么它会被归入半透明物体,而用户创建的Primitive如果不透明,则会在半透明物体之前渲染,从而遮挡Entity。
但是,如果两者都是不透明的,那么它们的渲染顺序就由添加顺序决定(在同一个集合中,先添加的先渲染,后添加的后渲染,后渲染的覆盖先渲染的)。
所以,用户观察到Entity在Primitive下面,可能是因为:
- 用户先添加了Entity(生成的Primitive),然后添加了用户创建的Primitive(不透明),所以用户创建的Primitive后渲染,覆盖了Entity。
- 或者,用户创建的Primitive被添加到了`groundPrimitives`集合(这个集合在地形之后渲染,但在`scene.primitives`之前),而Entity被添加到`scene.primitives`,所以`groundPrimitives`中的Primitive会先于`scene.primitives`中的Entity渲染,导致Entity覆盖Primitive。但用户观察到的是Entity在下面,所以这种情况不符合。
因此,最可能的原因是添加顺序:先添加Entity,后添加Primitive,导致Primitive在Entity之上渲染。
但是,用户的问题特别提到开启地形深度监测时出现这种情况。在没有开启地形深度监测时,物体之间的深度测试仍然存在,所以遮挡关系应该相同。那么为什么用户会注意到开启地形深度监测后才出现呢?可能是因为在没有开启地形深度监测时,Entity和Primitive都不与地形进行深度测试,所以它们可能都显示在地形之上(即使高度低于地形),这样它们之间的遮挡关系可能被地形遮挡所掩盖。而开启地形深度监测后,Entity和Primitive都正确地与地形进行深度测试,此时它们之间的遮挡关系就变得明显。
因此,结论是:开启地形深度监测后,Entity和Primitive的渲染层级关系(遮挡关系)主要由它们的添加顺序(在同一个集合中)和深度值决定。如果用户先添加Entity,后添加Primitive,那么Primitive会覆盖Entity(即Entity在Primitive下面)。要改变这种关系,可以调整添加顺序,或者使用`primitive.show`属性控制显示,或者通过设置`depthFail`外观来处理深度测试失败的情况。
最后,回答用户问题:开启地形深度监测时,Entity渲染在Primitive的下面,可能是因为用户先添加了Entity,后添加了Primitive,导致Primitive在Entity之上渲染。同时,由于Primitive的深度值可能更靠近相机(或者相同位置时由于后渲染而覆盖),从而遮挡了Entity。
建议用户检查添加顺序,并考虑调整添加顺序或设置Primitive的`depthFailAppearance`来改变显示效果。
生成相关问题:
1. 如何调整Cesium中Primitive和Entity的渲染顺序?
2. 地形深度监测对Cesium渲染性能有什么影响?
3. 如何设置Primitive的深度测试属性以避免被其他物体遮挡?</think>### Cesium中Entity与Primitive的深度渲染层级分析
在Cesium中开启地形深度监测(`terrainDepthTesting`)时,Entity渲染在Primitive下方的根本原因在于两者的**渲染管线差异**和**深度测试机制**。以下是具体分析:
#### 1. **渲染流程差异**
- **Primitive API**:直接对接图形底层(如WebGL),通过`PrimitiveCollection`管理,其渲染顺序由添加到场景的顺序决定(后添加的覆盖先添加的)。开启地形深度监测后,Primitive会参与**全局深度测试**,包括地形深度缓冲区。
- **Entity API**:Entity在底层被转换为Primitive(通过`EntityCluster`),但转换后的Primitive会被添加到**独立渲染队列**中[^1][^3]。该队列默认在原生Primitive之后渲染,导致Entity生成的图形被后渲染的Primitive覆盖。
#### 2. **深度测试机制的影响**
- 开启地形深度监测后,Cesium会生成**地形深度纹理**(depth texture),所有图形需与此纹理进行深度比较。
- Primitive直接使用深度纹理进行测试,其深度值计算基于**模型空间坐标**。
- Entity生成的图形需经过**额外的坐标转换**(因Entity绑定到时间动态数据),导致深度值计算延迟。当同一位置存在Primitive时,Entity的深度值可能被判定为“更远”[^2][^4]。
#### 3. **底层实现差异**
```mermaid
graph LR
A[Entity添加] --> B[EntityCluster转换为Primitive]
B --> C{添加到专用队列}
D[原生Primitive添加] --> E{添加到主队列}
E -->|渲染顺序| F[主队列先渲染]
C -->|渲染顺序| G[专用队列后渲染]
F --> H[深度测试通过]
G --> I[被先渲染的Primitive遮挡]
```
#### 解决方案(强制Entity在上层渲染)
```javascript
// 方法1:调整Entity生成的Primitive渲染顺序
entity.primitive = new Cesium.Primitive({
appearance: /* ... */,
renderState: {
depthTest: {
enabled: true,
func: Cesium.DepthFunction.LESS_OR_EQUAL // 修改深度比较函数
}
},
zIndex: 100 // 提高渲染层级
});
// 方法2:将Entity转换为Primitive并手动控制
const primitive = viewer.scene.primitives.add(
Cesium.Primitive.fromEntity(entity)
);
primitive.zIndex = 100; // 置于顶层
```
> **关键结论**:Entity因封装层导致的渲染队列滞后和深度计算延迟,使其在开启地形深度监测时易被Primitive遮挡。可通过直接操作底层Primitive的`zIndex`或修改深度测试函数强制调整层级[^3][^4]。
---
### 相关问题
1. **如何优化Cesium中Entity与Primitive混合渲染的性能?**
2. **地形深度监测开启后,如何调试深度测试失败的问题?**
3. **Entity API在哪些场景下不适合使用?应如何替代?**
[^1]: 官方教材中提到,Primitive API主要适用于图形渲染开发者,Entity API则适用于数据驱动的可视化,而Entity API的底层则使用了Primitive API。
[^2]: Cesium中Primitive与Entity详细介绍。Cesium为开发者提供了丰富的图形绘制和空间数据管理的API。
[^3]: entity是在primitive的基础上又进行了一次封装,对于开发者来说使用api更简单更容易。
[^4]: Cesium: Primitive vs Entity。Cesium | Primitive图元介绍及与Entity对比。
阅读全文
相关推荐



















