cesium加载SEM解决模型抖动问题
Cesium 高精度渲染:转换为局部坐标系的实现方案
在 Cesium 开发中,当需要渲染大量高精度模型或远离地球原点的模型时,经常会遇到浮点精度问题,导致模型抖动、撕裂或位置偏移。这种情况下,将模型转换为局部坐标系(Local Coordinate System)是一种行之有效的解决方案。本文将详细介绍如何在 Cesium 中实现世界坐标到局部坐标的转换,以提高渲染精度和性能。
为什么需要局部坐标系?
Cesium 默认使用 ECEF(Earth-Centered, Earth-Fixed)坐标系,即地心地固坐标系。这是一个以地球中心为原点的笛卡尔坐标系。当模型距离原点很远时,会出现以下问题:
- 浮点精度损失:JavaScript 使用 64 位浮点数,有效精度约为 16 位。当坐标值很大时(如地球表面点的 ECEF 坐标通常为百万量级),小数部分的精度会逐渐丢失。
- 模型抖动:精度损失导致相机移动时,模型会出现微小的抖动或跳跃。
- Z-fighting:深度缓冲区精度不足,导致表面之间出现闪烁。
局部坐标系通过将模型中心设为原点,大幅减小坐标值的绝对大小,从而保留更多小数位精度,解决上述问题。
实现原理
局部坐标系的核心思想是相对于中心点(Relative to Center,简称 RTC)技术。其基本步骤如下:
- 选择一个参考点作为局部坐标系的原点(通常是模型的中心点)
- 创建从全球坐标到局部坐标的转换矩阵
- 将所有顶点从全球坐标转换为相对于该原点的局部坐标
- 在渲染时,将整个坐标系一起变换回全球位置
代码实现
1. 创建局部坐标系
首先,我们需要为模型创建一个局部坐标系:
1 | const rtcCartesian3 = Cesium.Cartesian3.fromDegrees(rtcCenter[0], rtcCenter[1], rtcCenter[2]); |
这段代码的工作原理:
rtcCenter是局部坐标系的中心点,使用经纬度和高度表示Cesium.Cartesian3.fromDegrees将经纬度坐标转换为 ECEF 坐标eastNorthUpToFixedFrame创建一个变换矩阵,该矩阵定义了一个以指定点为原点、东北天为轴向的局部坐标系- 计算矩阵的逆矩阵,用于将全球坐标转换为局部坐标
2. 坐标转换函数
下面是将全球坐标转换为局部坐标的辅助函数:
1 | SemModel.prototype.worldToLocal = function (positionWC, result, modelMatrixInverse) { |
该函数通过将世界坐标点与逆模型矩阵相乘,将其转换为局部坐标系中的点。
3. 创建使用局部坐标的几何体
最后,我们将完整的几何体转换到局部坐标系:
1 | SemModel.prototype.createCityGeometry = function ( |
这个函数的工作流程:
- 遍历所有顶点
- 将原始坐标(此例中为 EPSG:4549)转换为 WGS84 经纬度(EPSG:4326)
- 将经纬度转换为 Cesium 的 ECEF 坐标
- 将 ECEF 坐标转换为局部坐标
- 创建几何体,使用转换后的局部坐标
cesium加载SEM解决模型抖动问题