站内搜索

输入关键词开始搜索

Cesium 地形抬升:从真实地表生成可编辑地块

文章目录

地形抬升保留区域内原有起伏,把整块真实地表整体提高指定距离,同时补出侧壁、底面和与周边地形连接的坑体。它不是一个平面盒子。

真实地形上的抬升区域参数、质量档位和边界编辑界面

实现思路导图

flowchart TD
  ROOT[地形抬升]
  ROOT --> INPUT[区域与抬升量]
  ROOT --> SAMPLE[原始地形采样]
  SAMPLE --> TOPGRID[顶部三角网]
  SAMPLE --> TEXTURE[区域影像纹理]
  ROOT --> GEOMETRY[封闭块体]
  GEOMETRY --> TOP[保形抬升顶部]
  GEOMETRY --> WALL[四周侧壁]
  GEOMETRY --> BASE[底面封口]
  ROOT --> REPLACE[裁剪原地形并提交 Primitive]

创建任务是一条异步管线

边界绘制完成后,TerrainLiftManager 依次完成地形采样、三角网构建、影像纹理获取和 Primitive 创建。页面通过进度回调展示当前阶段:

const manager = new TerrainLiftManager(viewer, {
  onProgress: (value) => {
    progress.value = value;
  },
  onLiftComplete: () => finishActiveOperation(id),
  onLiftError: (reason) => failOperation(id, reason),
});

质量档位控制边界点数、内部网格和纹理尺寸。快速预览适合调边界,高质量适合参数稳定后的最终展示。

顶面保留真实起伏

区域内部先采样原始高程。每个顶点的新高度是:

const liftedHeight = sourceHeight + liftHeight;

因此山脊、沟谷仍保留,只是整体上移。顶面三角网的 UV 来自局部包围盒,用于映射当前影像纹理。

影像纹理需要单独获取

TerrainTextureRenderer 按区域范围渲染或请求当前底图,生成顶面使用的纹理。相机截图不能替代这一步,因为截图包含视角透视和其他场景对象,无法稳定映射到地块 UV。

侧壁和坑体闭合地块

每个边界采样点至少对应原地表、抬升顶面和坑底三个高度。相邻点连接后分别形成地块侧壁与坑壁。边界顺序必须保持一致,重复首尾点也要在建网前统一处理。

多区域裁剪继续由共享管理器维护,避免一个地块覆盖另一个地块的 Globe 裁剪状态。

可取消和过期结果

高质量任务可能持续数秒。取消操作时不仅隐藏加载层,还要给任务标记失效。之后返回的采样或纹理结果必须检查任务 id,不能继续创建 Primitive。

if (activeAreaId !== request.id) return;

草稿与归档

草稿保存当前浏览器中的边界和参数;JSON 归档用于跨会话恢复。两者都保存可重建数据,不序列化 GPU 资源。恢复时重新执行采样和几何构建。

这个案例的主线是:采样真实地表 → 整体增加高度 → 生成纹理化顶面和闭合侧壁 → 用任务状态管理异步创建与取消。

截图中的抬升块怎样识别

截图中央的棕色地块已经离开原山体,边缘能看到从原地表到抬升顶面的侧壁。左侧区域列表出现“抬升 500m、坑深 300m、快速、4 点”,底部状态显示任务完成。

快速档位只使用 200 个边界采样和 32 级顶面网格,所以截图中的轮廓较粗。它用于验证几何和参数,不代表最终 2048px 纹理质量。

顶面不是一个平面

内部网格按多边形包围盒建立。每个有效顶点先采样原地形高程,再加统一抬升量:

liftedHeight(i) = sampledTerrainHeight(i) + liftHeight

因此原来的山脊和沟槽保留下来。所谓“整体抬升”是所有顶点增加同一高度,不是把区域压平成一个水平面。

无效网格点不会进入三角形。边界附近还要裁掉跨出多边形的网格单元,否则顶面会呈现包围盒形状。

为什么要俯视渲染影像纹理

顶面升高后仍需要原区域影像。案例在原地表上方建立正交俯视相机,把当前影像渲染到离屏纹理,再按区域包围盒生成 UV。

正交投影保证纹理比例与地面平面一致。使用透视相机截图会产生近大远小,贴到顶面后道路和山脊位置无法对齐。

纹理阶段需要临时修改相机和场景显示状态,所以必须保存并恢复主相机、裁剪和可见对象。取消任务时也要恢复这些快照。

闭合体由五部分组成

  1. 抬升后的真实起伏顶面。
  2. 顶面边界到原地表边界之间的地块侧壁。
  3. 原地表以下的坑壁。
  4. 地块自身底面。
  5. 原位置留下的坑底。

抬升高度和坑深分别控制不同高度段。把两者合成一个值会让“抬升 500 米、地块厚 300 米”无法表达。

质量档位改变哪些资源

档位参数影响
边界采样数侧壁与坑壁贴合程度
顶面精度内部三角网数量
纹理尺寸顶面影像清晰度
分批大小单次采样和构建阻塞时间

质量切换不是单个 Shader uniform,必须重新采样和构建。面板在任务开始前确定质量快照;创建过程中继续拖动参数,不会改变正在运行的任务。

异步任务的完成条件

一个区域只有在采样、纹理、几何、裁剪全部成功后才从 building 变成可编辑状态。任何阶段失败都销毁已创建资源并移除区域占位。

activeAreaId 用来淘汰取消后的回调。这只能防止结果提交,不能让已经发出的网络请求立即停止。进度条反映当前任务阶段,不是 Cesium 地形请求的精确字节进度。

从零复现:地形抬升教程

案例源码位于 src/demos/cesiumdemos/terrain-lift/。抬升不是把原地形顶点直接加高,而是隐藏目标区域原地形,再构建一个保留原表面起伏的封闭块体。

第 1 步:确定区域和抬升量

绘制多边形后转到局部 ENU,检查自交并计算包围范围。保存抬升高度 offsetHeight,同时记录质量档位对应的内部采样间距。

快速预览使用稀疏采样;最终质量再增加顶部网格密度。不要让拖动高度滑块每个像素都重新请求地形。

第 2 步:生成顶部采样点

在多边形包围矩形中建立规则格,保留多边形内部点,并把边界加密点一起加入。批量调用 sampleTerrainMostDetailed 获取原始高度。

完成标志:暂时以 PointPrimitive 显示样本,边界上无大间隙,山脊和沟谷处点高程变化连续。

第 3 步:三角化原始地表

在局部二维平面将内部点和边界点构造成三角网。每个顶点保留 originalHeight,抬升后的顶部高程为:

const liftedHeight = originalHeight + offsetHeight;

所有点加同一个偏移,因此顶部保留原山体起伏。若把全部点设置为同一高度,得到的是压平台,不是抬升块。

第 4 步:捕获并映射原区域影像

根据区域包围范围建立正交视图,捕获或请求原地形影像,保存为顶部纹理。顶部顶点的 UV 由局部包围矩形归一化得到。

uv.x = (localX - minX) / (maxX - minX);
uv.y = (localY - minY) / (maxY - minY);

先用棋盘纹理验证方向,再换真实影像。出现镜像时修正 V 坐标,不要旋转整个几何。

第 5 步:构建侧壁和底面

沿加密边界各生成原始高程点与抬升高程点,连接为侧壁。底面使用原边界或略低的封口面,使块体从任何视角都不露内部。

侧壁法线应朝外,顶面法线朝上,底面法线朝下。开启背面剔除后逐个视角检查,能快速发现三角形绕序错误。

第 6 步:隐藏原地形区域

使用与开挖类似的裁剪或遮罩移除原区域表面,避免抬升块下方仍显示原山体产生重叠。裁剪范围只覆盖当前区域,并保留其他区域已有状态。

第 7 步:提交完整资源包

只有地形采样、顶部纹理、顶面、侧壁、底面和裁剪都成功后,才把区域状态切为 ready。失败时按创建逆序销毁已完成资源。

高度调整可以复用原始样本和纹理,只重算顶点高度与包围体;边界或质量改变才重新采样和三角化。

验收与排错

  • 顶部变成平板:确认每个顶点保留自己的原始高程。
  • 顶部纹理倒置:检查正交捕获方向和 UV 的 V 轴。
  • 侧壁有洞:边界加密数组必须首尾闭合。
  • 抬升后相机靠近时对象消失:重算包含新高度的包围球。

相关文章

Cesium 地形可视域:径向采样与最大遮挡仰角

通过地形径向采样判断可见与遮挡区域,并生成观察点视角快照和计算统计

Cesium 地形可视域分析:用采样射线判断通视关系

不依赖 ShadowMap,从观察点建立径向采样网格,通过最大遮挡仰角计算地形可见区并细化红绿边界