1. 核心思路:为什么能用DEM搞出三维地形
1.1 DEM到底存了什么
先花一分钟把概念讲清楚,因为很多从Blender这边过来的朋友,第一次拿到DEM数据时完全是懵的——这不就是一张黑白图吗,怎么就成地形了?
DEM(数字高程模型)本质上是一个栅格数据,每个像素存储的不是颜色,而是这一格地面距离参考面(通常是海平面)的高度值。一个像素对应地面上一个真实的范围,比如30米乘30米或者90米乘90米,这个尺寸叫分辨率。所以DEM图面上每个点的明暗,代表的是这一格地势的高低:越亮越高,越暗越低。你用看图软件打开一张DEM的TIF文件,看到的只是一张灰蒙蒙的图,这是正常的,因为它的“rgb”通道被映射成了高度值显示。
这里就引出第一个关键点:TIF格式在这里不是一个花瓶容器。它可能是GeoTIFF,里面除了像素高度数据之外,还记录了坐标系、投影参数、地面分辨率、地图范围等一整套地理参考信息。也就是说,它不只是一张图,而是一张带着空间坐标的图。这个特性对后续的比例处理非常关键,后面我会单独讲。
顺便也把概念理一下:DSM(数字表面模型)和DEM不太一样。DEM是裸露地表的高程,DSM是包含建筑、树木等地物顶部的高程。做地形三维模型,一般用DEM;如果要做城市建筑群或者植被覆盖地区的表面模型,那用DSM也可以,但出来的边缘会比较乱,因为树冠和房顶会连成一片。我们这篇文章以DEM为主线,DSM的处理逻辑基本一样,就是表面细节变多,置换出来会更毛糙。
1.2 为什么选Blender做这事,而不是ArcScene或QGIS
做三维地形,传统GIS软件也能干。ArcScene能做,QGIS装个插件也能看个大概,但它们的渲染能力、材质系统和输出控制都太弱了,出来的模型大多是灰扑扑的色块,想做一张像样的地形图或者交互动画非常吃力。
Blender的优势在于它本身就是一个完整的数字内容创作工具链。模型、材质、灯光、动画、渲染,甚至视频剪辑都在一个软件里。地形建完之后,你不是只能干瞪眼看一个静态模型,而是可以直接给它合成卫星影像贴图、做早晚光照变化动画、输出带有海拔配色的分析图、导出给游戏引擎或3D打印。
代价是什么?Blender完全不认识地理坐标。它不知道经纬度,不理解UTM投影,更不懂“这个DEM范围是东西10公里、南北8公里”是什么意思。它只知道:你给我一张黑白图,我按灰度值把顶点抬起来。所以我们需要在进入Blender之前,把地理信息处理成Blender能理解的东西——一张比例正确、宽高比正确的灰度图。这是整个流程里最核心的一步。
1.3 整个流程一句话总结
先下载DEM数据,在GIS软件里做投影转换、裁剪、灰度拉伸,导出成一张比例正确的黑白图,然后导入Blender,用置换或顶点位移的方式把灰度图变成地形网格,再叠加卫星图或风格化配色,最后渲染或导出。每一个环节都不难,但顺序错了或者比例没控制好,后面返工的滋味非常酸爽。
提示:论文、工程汇报或地形分析场景下,建议保留原始DEM数据经投影转换信息,后续用Blender做出模型后,再回贴标注或坐标参考,避免甲方问“你这个小山头在哪个位置”时无法回答。
2. 数据准备与预处理:一半时间花在这关
2.1 DEM数据从哪里获取
做这个项目,第一步是拿到数据。常用公开数据源其实不少,我按易用程度排个序。
首推USGS EarthExplorer,这是美国地质调查局的地学数据下载平台,全球很多区域的DEM数据都能在这里找到。它有点像一个地学数据超市:你画一个范围框,选好卫星或数据集(比如SRTM、ASTER GDEM,以及一些更高分辨率的高程数据集),它就列出该区域可下载的影像和DEM。下载时注意选“GeoTIFF”格式,选好投影信息,一并用压缩包得到,不要下载成JPEG或PNG——那会丢失高程精度和坐标信息。
其次是NASA Earthdata,NASA的很多地形数据,比如NASADEM(SRTM的再处理版本)就在这上面。它跟USGS有点像,检索体系更科研一些,第一次上手可能需要一点耐心。
如果不想折腾注册和选框下载,还有一个相对偷懒的办法:AWS Terrain Tiles。这是一个把全球地形数据切成了瓦片、可以直接按需要的区域拼接下载的数据服务。对做可视化来说非常好用,得到的文件已经是处理好的高程瓦片,省掉了很多裁剪合并的功夫。但它面向的对象更偏开发者和数据工程师,命令行的操作方式可能劝退一部分纯设计背景的朋友。
下载的时候注意看几个要素:分辨率(一般有30米、90米可选,更高精度数据有10米甚至1米的,但覆盖范围小,下载量大)、坐标系(很多原始数据是WGS84经纬度坐标系,需要后续处理)、以及云量或空洞情况(有些地区原始数据有NoData空洞,显示为黑色区域)。我个人的选择习惯是:如果只是做可视化展示,90米分辨率足够用了,一个范围不大的流域,几兆文件搞定,Blender处理起来毫无压力。如果要做高精度的地形分析或近景特写,那就上30米甚至更高分辨率的。具体取舍看你的目标用途,没有绝对标准。
2.2 坐标与比例设置:比例不对,一切白费
拿到DEM后,最容易被忽略的就是坐标系和宽高比问题。如果你下载的DEM是经纬度坐标(地理坐标系),那么它的X方向(经度)和Y方向(纬度)的实际地面距离是不等价的。在低纬度地区,1度经度约等于111公里,但到了北纬60度,1度经度只有约55公里。如果你不看投影直接拿经纬度DEM去Blender置换,出来的模型东西方向会被拉长或压缩,山体形状全被扭曲。
解决方法是在GIS软件里做一步投影转换——把地理坐标系的DEM转成投影坐标系,比如UTM(通用横轴墨卡托)。UTM坐标系的单位是米,X和Y都是真实地面距离,这样转换后再导出灰度图,宽高比就真实了。
操作很简单。假设你用的是QGIS:加载DEM图层后,右键图层选择“导出”或“另存为”,在“CRS”选项里选择你所在区域的UTM投影带(以中央经线确定带号),然后确认输出格式是GeoTIFF。导出的新文件就是米制坐标的DEM。
为什么要做这一步?因为在Blender里你没办法告诉它“这个东西是经纬度数据,你按球面展开”,它只能用平面坐标。你给它的XY比例不对,山就歪了。而且这步处理还有另一个好处:后续从灰度图计算尺寸或缩放比例时,你可以直接在投影坐标下量出数据范围的东西距离和南北距离,填进Blender的平面尺寸里。
注意:如果你的DEM只是一个小范围的示例数据,而你并不追求真实地理空间精度,只想快速出个山形地貌看看效果,那经纬度直接导入也不是绝对不能做出形状来,只是比例会失真,不能用于需要精确比例尺的分析或展示。意识到这个区别,你就知道什么时候可以偷懒,什么时候必须处理。
2.3 把DEM转成Blender能用的灰度图
投影转换完成后,接下来就是导出灰度图。这一步的核心逻辑是:让每个像素的亮度值真实反映该处的高程。
用QGIS操作的话:先把你转好投影的DEM加载进来,在图层上右键选择“导出”或“另存为”,格式选“GeoTIFF”,然后在“渲染类型”或“渲染模式”里选“单波段灰度”(Singleband gray);在做这个之前,最好先用“拉伸”方式把灰度范围拉开,即使用2%到98%的线性拉伸方式,把高程值的最小和最大的极值排除,让山体阴影的细节充分拉开。这里有个关键操作:灰度图输出时建议选8位或16位,8位标准PNG/JPEG,16位TIF精度更高但要看后续软件支持情况——Blender支持,但贴图导入和显示上麻烦一些。一般可视化项目我用8位灰度PNG就够了,输出时注意不要选为JPG,因为JPG有损压缩会在灰度渐变区域产生条纹和色块,细节会丢。输出PNG是无损的。
做完这步,你会得到一张灰度的PNG文件,亮的地方高,暗的地方低。把这个文件放进Blender,它就是地形的“脚手架”。
3. 实操走起:在Blender里从零造出一座山系
3.1 两条路线:插件导入还是手动置换
进入Blender后,地形建模有两条主路线,分别适合不同情况。
第一条是插件路线:Blender自带了一个叫“A.N.T. Landscape”的插件,在“编辑-偏好设置-插件”里搜索enable即可。这个插件提供了一整套程序化地形生成方案,里面有一个“Import DEM”功能,可以直接加载DEM灰度图并生成地形网格。好处是快,选个文件、点几下就能出一个地形;坏处是可控性相对差一些,贴图UV、网格密度、置换强度的调整逻辑有点绕,如果你要做非常精准的尺寸控制,plugin默认帮你做的一些缩放反而成了麻烦。
第二条是手动路线:创建一个平面,给平面足够细分,然后添加一个Displace(置换)修改器,把灰度图作为置换纹理加载进去。所有参数自己控制,逻辑透明,出了问题也知道在哪改。缺点是步骤稍微多一点,但真的很直观,尤其对新手理解“用什么数据做出什么结果”这件事帮助巨大。我个人实际操作中,90%的情况都用手动路线,一是心里踏实,二是Displace修改器后面还可以实时叠加其他纹理来做细节,灵活性高。
本文重点讲手动路线,因为会的人多了,插件的坑也能避开。
3.2 从平面到地形:创建物体、细分和置换
第一步,新建一个平面(Plane),默认是2米乘2米。这一步的关键是比例。假设你的DEM投影后范围是东西5000米、南北4000米,那就把平面的X轴缩放设为5,Y轴缩放设为4。注意,这里的比例是相对的,你可以用1个单位代表1000米,也可以用1个单位代表100米,只要XY比例跟DEM一致就行,Z方向的强度是另一个独立参数,后面单独调整。
第二步,细分。选中平面进入编辑模式,右键选择“细分”(Subdivide),细分次数决定了网格密度。这里有一个实际体验:如果之后还要用Subdivision Surface(细分表面)修改器,可以先用较少的细分次数,比如2到3次,让平面网格稀疏一点,后面用修改器统一控制精度,省得直接细分后修改困难。如果不用细分表面修改器,直接用右键细分到足够密度,那建议至少细分7到10次,让网格规模接近百万级,实际取决于电脑配置。顶点数量越大,置换细节越丰富,但电脑越吃力。我的建议是先从低细分开始测试,参数调好后再提高分辨率做最终输出。
第三步,添加置换修改器。给平面添加Displace修改器,在Texture面板里新建一个图像纹理,加载我们的灰度PNG。如果平面尺寸和图片比例不对,置换图案会出现拉伸变形,这就回到前面说的宽高比问题——所以先把XY比例调正确再置换,纹理坐标才会对得上。加载后,Displace修改器的Strength(强度)参数先设为默认1,这时候你可能会看到地形像一个小土包或者一个大窟窿,因为强度还没有按比例缩放到真实高度范围。
3.3 置换强度怎么算:高差与单位的换算
置换强度的计算其实不复杂。换到前一步的例子里:如果DEM范围内的最高海拔减去最低海拔等于800米,而你设定的Blender单位是1个单位等于100米,那置换强度应该设为8左右(800/100=8)。但实际上还有一个变量:灰度图的黑白亮度范围是否被拉伸到0到1之间。
这里有个很容易犯迷糊的地方。Blender里,Displace纹理会用灰度图的明暗值作为位移因子:黑色(0)不位移,白色(1)位移最大。如果你的灰度图高程值分布是500米到1300米,但你把拉伸拉伸成了全黑到全白,那么整个地形的高程区间就映射到了0到1,那样会导致最低点和最高点形成巨大高差。正确的做法是在QGIS导出灰度图时就做了2%-98%线性拉伸,这样高程中段压缩相对合理,再用强度换算回实际高差就行。
实际操作中我一般是这么做的:先设一个大致强度,观察地形是否“被压扁”或“拉尖”,再根据渲染效果微调。如果你的项目需要精确的高程比例,那就要用“Geometry Nodes”(几何节点)或者Script精确控制顶点偏移,这部分偏进阶,后面再展开。
3.4 Subdivision Surface与网格细节的取舍
地形网格做出来后,表面往往会有明显的棱角和阶梯感,即便用了灰度图置换,因为网格顶点数量有限,坡度转折处还是会出现多边形感。解决办法是用Subdivision Surface修改器把网格平滑一次,再用Shade Smooth(平滑着色)处理视觉效果。
注意顺序:Subdivision Surface要放在Displace修改器之前还是之后,效果不一样。我的经验是:如果细分表面放在Displace之前,它会先细分网格再置换,细节波动会更平滑,产生的顶点密度也高;如果放在Displace之后,则置换只在原始网格上发生,再细分相当于纯平滑,表面细节量不变但形状更柔。一般我推荐“细分表面在前、置换在后”,让置换发生在高密度网格上,山脊和沟谷的形态会更自然。
网格细节和性能是直接矛盾。要想细节丰富又不卡顿,我的做法是先用低细分网格搭好整体比例和置换强度,确认没问题后,再把视口显示用较低的分辨率预览,输出之前临时拉高渲染细分。或者直接给Subdivision Surface修改器设置一个“渲染”级别和“视口”级别——渲染级别设为2或3(高细节),视口级别设为1或0(低负载),这样编辑时不卡,输出时保证精度。Blender较新版本对这个支持很好,强烈推荐这个工作流。
实操心得:初次导入DEM置换后,地形方向可能与数据原始方向不一致(例如东西走向变成南北走向)。这是纹理坐标和物体旋转的问题:旋转平面物体90度即可,或者在Displace修改器里调整纹理坐标的映射方向。不要试图去旋转灰度图本身,那样会引入重采样失真。
4. 让地形有血有肉:卫星影像贴图与海拔配色
4.1 给地形叠加卫星影像
一张灰白色的三维地形也能看,但叠加了真实地表影像之后,观感直接上了一个等级。叠加卫星影像的核心是UV对应问题:我们需要让影像的每一个像素在三维模型上找到正确的位置。
有两种方式:一种是在灰度图导出时,同时把对应范围的卫星影像也导出成同一范围、同一投影坐标、同一分辨率的图片文件,然后在Blender里给模型新建材质,把影像作为基础色纹理加载,并把纹理坐标设为“生成”(Generated)或“UV”模式。这种方式要求灰度图和影像图的范围完全对齐,操作的关键是在QGIS里用相同的裁剪范围、相同的投影坐标输出,这样两张图的XY比例就一致了。
还有一种方式是直接把影像文件拖进Blender的纹理节点中,让模型根据自己的UV读写。默认平面UV本来就是完整覆盖整个物体的,如果DEM和影像比例一致,UV映射基本就是对的;如果不一致,会出现影像拉伸。这个方式适合你只拿测试数据快速预览的情况,出正式成果我还是建议用第一种。
在材质节点的处理上,我的经验是在基础色后面接入一个颜色渐变节点,把图像颜色分层,这样可以让部分场景看起来更像地图而不是纯照片。这个主要看你想要“真实感”还是“制图感”。
4.2 按海拔高度着色:从地形到专题图
除了卫星影像,海拔配色是最常用的表达方式,就是低海拔区域用绿色,中海拔用黄褐色,高海拔用白色,像等高线分层设色图。
实现方法不复杂:在Cycles或EEVEE的材质编辑器里,用纹理坐标(Texture Coordinate)节点获取物体的“物体坐标”,然后把它的Z通道单独提出来,经过一个Map Range(映射范围)节点,把我们的实际海拔范围(比如最低点200米,最高点900米)映射到0到1,再接上一个ColorRamp(颜色渐变)节点,设置几个颜色断点:低处绿色、中间黄褐、高处白色或灰色。这样模型表面就会根据海拔动态上色。
这个做法的好处是:你再也不用回到图像处理软件里做“等高线填色图”,直接在三维模型上实时着色,切换视角也不会出问题。更进一步可以把ColorRamp的滑块数量做多一些,模拟出更细腻的地带性过渡。
比较进阶的玩法是把“坡向”计算也加进来,比如南坡偏暖、北坡偏冷,在三维地形可视化里非常惊艳。Blender里可以用几何节点的法向信息做AO和坡向混合,因为操作树比较长,更适合会的朋友直接写节点组,这里先把思路说出来,有需要的可以顺着这个方向去查更详细的教程。
4.3 灯光与渲染:让起伏“说话”
地形模型做好了,材质也调好了,如果打光不对,所有细节全白搭。做地形渲染时,我最常用的是“太阳光”加“环境光遮蔽”的模式。太阳光从侧上方以大约30到40度的角度照射地形,这样山体的一面被照亮、另一面落暗沟,地形起伏感最明显。正上方顶光打下来,模型看起来像一个平面,细节全被抹平;正下方逆光会造成大面积死黑,也不好用。
环境光遮蔽(AO)在EEVEE和Cycles里都有选项,打开后山谷和裂缝交接处的接触阴影会加强,整个地形的立体感会立刻提升。如果你用的是Cycles渲染器,还可以加一个HDRI环境贴图作为微弱补光,但强度不要盖过太阳光,否则地形细节又会变得“平”。动动太阳角度,你会发现一座山的山脊走向一下就“跳”出来了。
渲染输出时,如果要做后期合成,相机可以用正交投影,出图比例设置为数据范围的宽高比,这样出来的几乎就是一张标准的地形测绘图,可以叠加文字、指北针、比例尺在后期软件里完成。
5. 常见问题与排查:我踩过的坑,你尽量别再踩
做DEM地形这个事,坑特别多。我把自己实际遇到过的、身边朋友也反复遇到过的几类问题集中列一下,附上解决思路。有些问题你搜半天搜不到答案,其实原理很简单,就是没人把这些细节写明白。
| 现象或报错 | 原因 | 排查与解决思路 |
|---|---|---|
| 地形东西方向被严重拉长或压扁 | DEM还是经纬度坐标系,X/Y单位不一致 | 到QGIS里转投影坐标系(UTM或高斯克吕格),再导出灰度图 |
| 置换出来的地形像“纸片”或者“一根刺” | 置换强度与模型比例不匹配,高差被放大或压缩 | 计算实际高差和模型单位比例,微调Strength;可用Map Range精简后再喂给位移 |
| 地形细节很糊,山脊沟谷消失 | 细分次数不够,灰度图分辨率太低,或灰度拉伸不够 | 提高细分级别;使用带16位精度的DEM导8位灰度时做好拉伸 |
| 模型表面有严重的锯齿和杂色条纹 | 8位灰度保存成JPG格式导致压缩伪影 | 统一用PNG/TIF无损格式,不要用JPG |
| 卫星影像贴图位置对不上模型 | 影像和DEM范围或投影不一致 | 回到GIS,保证两者同一投影、同一范围、同一像素分辨率再输出 |
| 在Blender里看挺好,导入其他软件地形变形或材质丢失 | Blender的置换和颜色渐变节点不兼容外部软件 | 把地形导出前先应用修改器,并将漫反射颜色烘焙到贴图再导出 |
| 一次细分太多导致电脑卡死 | 顶点数过多,内存爆了 | 先在视口级别用低细分,渲染级别设高;或者改用Decimate优化网格 |
| 模型底部看穿,没有“厚度” | 地形是一个曲面片,没有实体厚度 | 添加Solidify修改器,给地形一个薄壁厚度,输出到3D打印或游戏引擎时才有体积感 |
还有一些比较隐蔽的问题也值得注意:
一个是灰度图的方向问题。有些DEM数据处理后上下翻转了,但在Blender里你根本看不出来,直到你叠加卫星图后才发现山脉走向反了。解决办法:进入编辑模式全选网格后,旋转180度(或者对纹理坐标做一次旋转),不要在图层面板里硬翻,容易再次弄混方向。
另一个是NoData空洞问题。前面提到有些DEM区域有数据空洞,在GIS里如果不处理,导出的灰度图在空洞区域是纯黑色,置换后这里就直接塌成坑。处理方式是在QGIS里做“插值填充”或设置NoData为0值或平均值。不然你辛苦做的地形里,会莫名其妙出现一个规则的深坑或尖峰。
还有一个关于Modifier顺序的坑:Subdivision Surface和Displace的顺序错了,效果差异很大。我前面讲过“细分表面在前、置换在后”可能更平滑,但如果你希望保留明显的棱线(比如台阶状地形),那置换在前、细分在后会更合适。这个没有绝对标准,完全看你想表达什么。
6. 做完之后还能干点啥:模型的延伸应用
6.1 导出给游戏引擎或GIS平台
Blender不是终点,把地形模型导出到其他平台有时候才是刚需。
如果目标是Unity或Unreal,推荐导出FBX格式,注意先把Displace和Subdivision Surface都“应用”(Apply)掉,并把材质烘焙成一张漫反射贴图,这样引擎里直接用PBR材质接收,效果基本和Blender一致。不烘焙的话,引擎不一定支持Blender的程序化节点,材质大概率会丢。
如果目标是Cesium或WebGIS之类的平台,通常需要把地形转成3D Tiles或量化的地形格式,那就得借助第三方工具链处理,Blender这边只需要保证网格拓扑和UV干净,方便它后续切块。
如果目标是3D打印,那么关键操作是给地形加Solidify修改器做一个底座,把Z轴比例按打印尺寸再调整一遍,导出STL格式。打印出来时记得把地形底部做平,不然摆放不正。选料和层高会影响细节表现,这个跟普通3D打印技巧一样,不赘述。
6.2 还可以做风格化场景和动画
不是所有DEM地形都必须走“真实感”路线。我见过有人把DEM置换结果配合Low Poly风格的材质(简单颜色平铺加描边),做出很精美的俯视地图动画;也有人把DEM和气象数据叠加,做出展示降雨量或气温分布的三维可视化;还有人用Blender的镜头动画,围绕山体做螺旋上升的展示视频,效果很惊艳,本质上只是一个DEM加一个摄像机动画而已。
如果做风格化,我推荐给材质加适当的噪波纹理和颜色渐变,让地形颜色看起来像手绘的等高线图,别一上来就贴真实卫星图。很多作品就是因为什么都想要真实感,结果看起来特别像一块“绿色马赛克”,反而没有手绘风格耐看。
6.3 个人经验密度最大的三个建议
第一,保持“源数据”干净比任何后期技巧都重要。投影转换、范围裁剪、分辨率统一,这些GIS侧的工作做扎实了,到Blender里就是一路顺畅。反过来,后面花十倍时间修补扭曲模型,只是治标不治本。
第二,Blender文件里请保持一套成体系的命名,比如“DEM_Projection”“DEM_Gray”“Satellite_Diffuse”,不然做复杂场景的时候,几十个节点和贴图混在一起,找个文件和参数会找崩溃。这听着像废话,但做复杂项目时我自己也常常栽在命名混乱上。
第三,如果对某个参数的变化没有把握,就按“先小代价大,再缩小代价验证”的思路来。我一般测试用低细分、低分辨率贴图,确认形态没问题后再开全精度,这样能省下大量等待渲染的时间。很多人一上来就套8K卫星图和百万级网格,电脑风扇转得比飞机发动机还响,最后改一个参数要等三分钟,基本等于白干。
这个项目的魅力在于它把地理信息、三维建模、材质表现几个不同领域的技能串到了一起,做熟练之后,你既能看懂地形数据的质量,也能输出让外行觉得“好厉害”的三维作品。如果后续你想深入,可以继续研究几何节点做动态地形,或者借助Blender的合成器直接出图,每一步都能带出新的玩法。