Skip to content

v0.2.8

Choose a tag to compare

@github-actions github-actions released this 05 Aug 18:16
· 163 commits to master since this release

v0.2.8 —— 地形的四个静默失败修复 + 界面可切英文 + 切片进度终于看得见(已有地形瓦片必须全部重切)

先说结论:已经切好的地形瓦片必须全部重切,否则地形部分的修复对你没有任何效果。 四个互相独立的原因,任何一个单独成立都要求重切。界面语言、切片进度、启动清扫这三块与瓦片无关,升级即生效。

原因一:此前的地形瓦片 Cesium 根本解不出来 —— 地形从未真正渲染过

  • quantized-mesh 里的 triangleCount 字段被写成了索引元素数(正确值的 3 倍),读端按它去取索引直接越界报错。全程静默:瓦片请求全部返回 200、任务标记完成、页面不报错,只是地形出不来。
  • 这一版修好了写瓦片的代码,但已经写在磁盘上的瓦片仍然是坏的 —— 那个错误的数字就在瓦片字节里。

原因二:这一版往瓦片里新增了法线数据与择优三角化,旧瓦片里没有这些内容。

原因三:相邻瓦片接缝处的高程此前对不齐

  • 取样时的降采样格子跟着「这一批点的外框」走,而相邻两张瓦片的外框不同 —— 于是同一个经纬度位置,在左边那张和右边那张里被采成了不同的高程。合成数据实测公共边最差 20.2 米,真实山地在中间缩放层级上平均 3.4 米、最差 16.8 米(最高精度层刚好不触发降采样,所以那一层是准的)。
  • 表现是相邻瓦片交界处的地形对不上,以及开光照后接缝处的明暗断层。
  • 已修:降采样格子改为锚定在源数据的像素网格上,与请求范围无关。修复后同一批真实瓦片的 543 对相邻边全部逐点一致。这条改变了所有瓦片的高程取值,所以旧瓦片必须重切。

原因四:用多幅 DEM 拼出来的地形,接缝处最大差了 50.9 米

  • 只影响一个任务里有多幅 DEM 的情况(比如下载一片跨好几个 1°×1° 分幅的区域)。单幅不受影响。
  • 表现和原因三一样是接缝对不上,但根子完全不同,所以修完原因三之后它还在。实测 6 幅拼的天山地形,在某一个缩放层级上有 16 对相邻瓦片的公共边对不齐,最大 50.9 米
  • 原因说起来有点绕:DEM 文件里通常预存了几张缩略图(不同倍率的低分辨率版本),程序按需要的精度挑一张用。ASTER 数据预存的倍率是 2、3、4、7.988.98、16、63、80 倍 —— 有几档挨得特别近。而把多幅拼在一起读取时,程序会把请求拆给各幅分别处理,拆完之后「需要多少倍」这个数字就不再整齐了,于是相邻两张瓦片可能一张挑了 7.98 倍那张缩略图、另一张挑了 8.98 倍的。同一个经纬度,读到了两个不同精度的数据。
  • 已修:一个任务里有多幅 DEM 时,先把它们合并成一个完整文件再切,并且重新生成一套倍率规整(2/4/8/16…)的缩略图。修复后同一批数据 8565 对公共边(含横向与纵向)全部精确为零。
  • 顺带变快了:合并后低缩放层级的取样从每张 2.3 毫秒降到 0.2 毫秒。
  • 代价:切片期间临时多占一份磁盘,切完自动删除。留量按数据源估:ASTER 实测约为源的 78%(6 幅 118 MB 的数据多占 92 MB),而默认的 Copernicus GLO-30 精度更高,约为源的 1.9 倍 —— 按后者预留更保险。空间不够时这一步会直接报错并清掉半成品,不会留下残骸,也不会交出一份缺数据的地形。

另一个静默失败:地形高程整体是错的

  • layer.json 里的 parentUrl 默认值以 /layer.json 结尾,而 Cesium 把这个值当目录用(自己再拼一次 layer.json),于是请求 404。Cesium 对这个 404 不报错,而是塞进一个假的高程图图层,并且这个错误假设会污染整个地形数据源 —— 连任务自己的瓦片也被按错误格式解析。
  • 实测:4154 米的山峰被解成海平面以下 744 米,而页面一切正常、控制台一条错误都没有。
  • 已修,但同样只对新切的瓦片生效:存量 layer.json 里写死的还是坏值。配置表里那一行也仍是旧值(这一版改的是新建数据库的默认值,不动已有的行),不过写 layer.json 时会统一规整一次,所以重切就能兜住,不需要手动去改配置。

逐顶点法线与地形光照开关

  • 每张瓦片额外写入逐顶点法线(每个顶点 2 字节)。地图工具栏多了一个「光照」按钮,默认关闭:它是纯渲染端开关,开关不需要重切瓦片。开着会与卫星影像自带的光照叠加,未必好看,所以数据先备着、什么时候开由你决定。这个偏好只存在浏览器本地,不进配置表。

全球底图现在随包分发,不用再自己准备

  • 以前的全球底图要你自备几 GB 到上百 GB 的全球高程数据自己切;这一版直接把切好的底图打进了安装包(GEBCO 2024 数据源,覆盖全球含海底地形,带法线)。
  • 首次使用前要还原一次,把 assets/terrain/ 里的两个分卷拼回 downloads/terrain/base_z8/⚠️ 下载 exe 的用户目前没有现成脚本可用(还原脚本只在源码仓库里,且需要 Python 环境),请在解压目录下手工执行一次:
    • Windows:copy /b assets\terrain\base_z8.tar.gz.partaa+assets\terrain\base_z8.tar.gz.partab base.tar.gz 然后 tar -xzf base.tar.gz -C downloads\terrain(Windows 10 起自带 tar)
    • Linux / macOS:cat assets/terrain/base_z8.tar.gz.part* > base.tar.gz && mkdir -p downloads/terrain && tar -xzf base.tar.gz -C downloads/terrain
    • 从源码运行的话直接跑 uv run python scripts/unpack_base_terrain.py,它会自己判断是否已还原。
      还原后 downloads/terrain/base_z8/ 下应有 layer.json 与 z0~z7 八层目录,中间文件 base.tar.gz 可以删掉。
  • 不还原也不会出问题 —— 切片时检测到底图缺失就不写那个级联地址(这正是上面「原因二」那个坑的修复)。只是镜头拉到高程数据范围之外时没有地形。
  • 分成两卷是因为打包后 167 MB,而 GitHub 单文件上限是 100 MB。
  • ⚠️ 如果你手上有 2026-08-05 之前自己切的旧底图,它里面没有法线。开光照后它覆盖的区域会显示为近乎纯黑的一块 —— 用上面的还原脚本换成新的即可。

三角化:逐瓦片挑更小的那一个

  • 新增了自适应三角化(Martini/RTIN),能按地形起伏把三角形数减掉八成。但不是无条件用它:实测 11 万张配对瓦片,压缩后山地反而涨 17.6%、丘陵涨 9.8%,只有平缓地形省 54.2%。原因是瓦片以压缩形式落盘和传输,而压缩后规则网格每个三角形只占约 0.91 字节、Martini 要约 4.04 字节,贵 4.4 倍 —— 减面必须超过 77% 才能在体积上打平,山地做不到。
  • 所以最终做法是:每张瓦片两种都编一遍,取压缩后更小的那一个。单张瓦片的体积不可能比原来更差。
  • 高程精度一步没让:误差预算参数保持原值,没有为了省体积去放宽它。

界面可以切英文了(zh / en)

  • 配置页「外观」区块多了一个「语言」开关,两个选项:中文 / English。切换后整页刷新一次(页面是服务端渲染的,语种必须先到服务端)。偏好存在浏览器 cookie 里,默认中文。
  • 覆盖范围:所有页面文案、按钮、提示气泡、接口返回的错误与确认文本、以及填错参数时的即时校验提示。刻意不翻的三类:日志、启动时那段控制台横幅、以及后台任务写进数据库的错误文本 —— 它们是给排查问题用的,写进去那一刻的界面语种说明不了将来是谁在看。
  • 漏翻不会静默:翻译表里查不到的词条,界面上直接显示词条名(形如 js.tasks.status.running),而不是偷偷回落成中文。
  • 英文界面下地图工具条的按钮会按文字宽度自动伸展 —— 英文标签比两个汉字宽一倍不止(Settings / Zoom out 约 44~52 像素),原来 32 像素的方按钮会把它裁成「etting」。中文界面的按钮尺寸一个像素没动。

地形切片的进度终于看得见

  • 此前的实际情况:下载任务显示「已完成」之后,切片还要再跑几十分钟到几小时,而这段时间任务行上什么都不显示 —— 后端一直在广播进度,但前端根本没人监听,只能靠手点详情弹窗刷新才看得到。
  • 现在任务行会实时显示「合并 DEM 43% …」「建金字塔 …」「切片中 1204 / 8192 …」。本地地形任务此前连进度回调都没接,这次一并补上。
  • 为什么分成两种文案:合并 DEM、建金字塔、等高线重投影这几步跑在「总共有多少张瓦片」算出来之前(要先有合并后的栅格才能建采样器,有采样器才知道总数),压根没有分母,所以只能报百分比;进入瓦片循环之后才有 n/m。

启动时会清掉上次没删干净的中间文件

  • 上面「原因四」的合并会在切片期间临时生成一份与源数据同量级的中间文件(GB 级任务就是 GB),正常结束会自己删。但直接关窗口或强杀进程时删不掉,会一直占着磁盘。
  • 现在启动时会扫一遍并清掉它们。判断「这份文件还有没有人在用」看的是文件名里记的进程号而不是修改时间 —— 中间文件写完时间就冻住了,而切片还能再跑几小时,按时间判断几乎必然误删。写它的进程还活着就跳过。
  • 扫描范围包含数据库里记录的任务输出目录(DEM 任务的输出是你自选的全盘路径,不一定在程序目录下)。

其他

  • 底部状态栏改成悬浮胶囊(不再占一整行布局),窄屏下自动收紧。
  • 启动横幅不再打印数据库路径。

代价

  • 切片 CPU 增加约 36%(算法线 + 两种三角化各跑一遍)。换来的是法线数据与逐瓦片最优的字节数。
  • 瓦片体积因法线而增大:压缩后规则网格分支 +55.4%、Martini 分支 +22.5%。

验证

  • 1192 项测试全部通过(Linux / Windows / macOS 三平台 CI 各跑一遍)。
  • 浏览器端实测:真实 DEM 切片后经 HTTP 取回,Cesium 解出的高程与源 DEM 交叉验证 —— 源 DEM 真值 2672 / 1086 / 4154 米,Cesium 读到 2658.7 / 1092.9 / 4161.9 米;法线段完整,长度与顶点数逐张对得上;随包的全球底图同样逐层验过(法线齐全、级联接得上、没有退化成错误格式)。

通用说明

  • 下载安装:从下方 Assets 下载对应平台压缩包(terraforge-windows.zip / terraforge-linux.tar.gz / terraforge-macos.tar.gz),解压即用,无需安装 Python 环境。
  • 这一版下载体积明显变大(每个平台约多 167 MB):全球底图的分卷随包分发,见上文「全球底图现在随包分发」。
  • 首次运行:启动可执行文件后,浏览器访问 http://localhost:5000 ;代理、并发、缓存管理等在「配置」页修改。
  • 历史版本:完整更新历史见仓库 CHANGELOG.md
  • 使用文档:见仓库 README.mddocs/guides/QUICKSTART.md