Terrain(地形) Geometry Clipmap

本文介绍了一种名为Geometry Clipmap的技术,该技术通过预过滤高度图并将其存储为多层次细节(mipmap),实现在大型室外场景中高效渲染地形。文章详细阐述了如何通过不同层次的顶点样本页面来适应视点变化,同时解决了页面间的裂缝问题。

在大的室外场景中,地形的几何体需要较大的存储空间和渲染带宽。为解决这个问题,出现了很多LOD的技术。然而,大多数技术都是在CPU端实现的,需要运行时创建和修改顶点缓冲区。

 

Geometry Clipmap:

把地形当做2D的高度图,并把它预过滤进一个L层的mipmap中。对于大场景来说,完整的地形mipmap太大,无法全部加载。所以 Clipmap会在每层缓存一个nxn顶点样本的页面,页面以视点为中心。这里需要注意的是:每一层的顶点都是nxn,也就算是每一层的三角形数量是一样的,只不过大小不一样,所以每一层表现出的面积也不一样,目的是让三角形在屏幕空间中的大小一样。视点移动的时候,对nxn的顶点数据进行更新,采用的是环形方式访问。

 

除了第一层以外,其他的层都是一个空心环,”回“ 字

这里看起来,每个外环的三角形是内环的4倍大小。

 

裂缝问题的解决:

每一层网格的大小一定是奇数,最好是(n = 2幂k - 1) 因此一般取n = 255。为啥要是奇数呢?主要是为了上一层有一部分覆盖到下一层上。

这里采用细的层次多出一个边的方式,对粗的层次进行覆盖,这里只增加一行一列是因为重心位置做了偏移,应该是用0.5格来覆盖边缘部分。这个图很重要,它告诉你每一个环由那些块组成的,把环算出来了,所有的环都可以进行类推。这个橙色的部分,是两块的接壤部分,采样的是退化三角形,本身是不怎么站面积的。

对于每一层执行了14次draw 其中12次灰色区块,1次内部调整,1次剩余的三角形。每帧总体需要:6L+5  L为层数。

另外,由于外层的面积是内层面积的2倍,所以内存只移动1格的时候,外层是不需要移动的。难道这才是为奇数的真正原因?

 

总结:一个无限大地形的世界场景如何实现呢?

1.首先,假设世界地图是无限大的,那么你肯定无法全部加载。所以,加载到内存的时候,是9个地形块,其中最中间的一个是当前使用的地形块,而其它8个是缓存起来备用的,这个类似九宫格。

2.根据当前视角的位置,加载当前使用的地下块到显存里面去,这加载的部分就是上面的mipmap,回字格L层,包括高度和法线数据。

3.draw 按照上面画的一个环裁剪后6次,这个裁剪是在CPU端计算的。这一步完成后基本上结果已经显示出来了。

4.视点位置移动时对数据进行更新。

这样基本上就可以实现一个无限大的世界了。

在 Cesium 中加载 `.terrain` 格式的地形数据,是通过使用 `CesiumTerrainProvider` 来实现的。`.terrain` 是 Cesium 官方支持的一种地形数据格式,通常由 [Cesium ion](https://cesium.com/platform/cesium-ion/) 或者使用 [Cesium Terrain Builder (CTB)](https://github.com/geo-data/cesium-terrain-builder) 工具生成。 --- ### ✅ 示例代码:加载 `.terrain` 地形数据 ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://cesium.com/downloads/cesiumjs/releases/1.111/Build/Cesium/Cesium.js"></script> <link href="https://cesium.com/downloads/cesiumjs/releases/1.111/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> </head> <body> <div id="cesiumContainer"></div> <script> // 设置 Cesium 静态资源路径 Cesium.Ion.defaultAccessToken = 'YOUR_ION_TOKEN'; // 如果使用 ion 服务 const viewer = new Cesium.Viewer('cesiumContainer', { terrain: Cesium.Terrain.fromWorldTerrain() // 默认使用 Cesium 全球地形 }); // 加载本地或远程的 .terrain 地形数据 const terrainProvider = new Cesium.CesiumTerrainProvider({ url: 'http://localhost:8000/path/to/your/terrain-root', // 指向 .terrain 文件的根目录 requestWaterMask: true, // 如果需要水体效果 requestVertexNormals: true // 如果需要光照效果 }); viewer.terrain = terrainProvider; </script> </body> </html> ``` --- ### 🔍 代码解释: - `CesiumTerrainProvider`:用于加载 `.terrain` 类型的地形数据。 - `url`:指向地形数据的根目录,通常是一个包含 `root.terrain` 和多个 `.terrain` 分块文件的服务器路径。 - `requestWaterMask`:启用后可以渲染水体效果(如河流、湖泊)。 - `requestVertexNormals`:启用后可以渲染光照效果,使地形更立体。 - `viewer.terrain = terrainProvider`:将新的地形设置为当前 Viewer 使用的地形。 --- ### 🧰 如何构建 `.terrain` 数据? 你可以使用 [Cesium Terrain Builder (CTB)](https://github.com/geo-data/cesium-terrain-builder) 将 DEM(数字高程模型)文件(如 GeoTIFF)转换为 `.terrain` 格式。 #### 示例命令: ```bash ctb-tile -f Mesh -C -o output_dir input_dem.tif ``` - `-f Mesh` 表示生成 `.terrain` 网格数据。 - `-C` 表示压缩地形数据。 - `output_dir` 是输出目录。 - `input_dem.tif` 是输入的 DEM 文件。 --- ### 📁 `.terrain` 目录结构示例: ``` terrain-root/ ├── root.terrain ├── 0/ │ └── 0.terrain ├── 1/ │ └── 0.terrain │ └── 1.terrain ... ``` 你需要将该目录部署到一个支持跨域请求(CORS)的 Web 服务器上,例如使用 Python 简单服务器: ```bash cd terrain-root python3 -m http.server 8000 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值