记一次Cesium排错

最近遇到一个贴模型 entity 导致,倾斜摄影渲染出现异常的问题,记录一下排错过程。

问题描述

首先,我只是使用 Cesium,并不涉及扩展开发。

问题出现的场景是这样的,我在 Vue 项目中使用超图 iClient for Cesium (基于 Cesium 扩展),向球体添加了一个 s3m 格式的倾斜摄服务。项目中有测面的功能,其中有一步会绘制一个贴模型的面类型 entity。意想不到的情况出现了,在我完成绘制的时,倾斜摄影的颜色渲染出现了异常,原来红色的部分似乎被覆盖了一层蓝色。

如图所示,万达广场的牌子颜色都变成蓝的了。

解决问题

首先,要排除 iClient for Cesium 包本身不存在问题,于是我写了一个单页面,添加了同样的 s3m 服务。并且实现了一下绘制贴模型面的功能。结果发现,这个页面没有预想中的异常。

这就说明我项目中的代码造成了这个异常。基于我的推断,能造成这样异常的代码应该存在于我们实现的绘制功能里,于是先大量注释无关代码,逐步释放,最终却定位在了绘制完成的回调事件上,只要不执行回调事件,就不会出现异常。这个回调事件将绘制得到的 entity 对象进行了返回。所以这个问题与绘制本身没有关系,也没有在绘制功能中做影响渲染的操作。

排查使用绘制功能的组件时,最终确定到了一行代码。这行代码的功能很简单,在 Vue 组件的 data 对象中定义有一个变量,这行代码将这个 entity 对象赋值给了这个变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
data() {
return {
entity: null,
};
},
methods: {
draw() {
// ...
this.entity = entity;
},
},
};

想来已经知道问题所在了,Vue 的响应式机制和 Cesium 的渲染机制产生了冲突,刚好我们绘制的面是贴模型面,会影响倾斜摄影服务的渲染,最终表现成了这个问题。最终只要避免将 entity 对象进行不必要的转换就不会出现渲染异常。

总结

其实早该想到可能有这样的问题,毕竟 Vue 的响应式机制和 Cesium 的渲染机制都是很复杂的,两者的结合必然会产生一些问题。比如先前将 Viewer 对象响应化,会导致整个球体出现大量卡顿掉帧,且页面 Vue 组件的渲染也会十分卡顿,也是类似的问题。

很多时候,我们其实并不需要 Vue 的响应式机制,只是为了方便调用,牺牲了一些性能。Vue 3 当中的 markRaw 方法,可以将对象标记为非响应式的,可以比较有效的解决这个问题。在 Vue 2 中,遇到像 Cesium 这种会产生严重错误的,只能采取绕行方案了。