Blender地形建模教程:从DEM灰度图到三维地形的Displace置换流程 1. 从GIS数据到三维网格先把核心思路理清楚做地形三维模型这件事我最早是在GIS软件里硬啃的。拿ArcScene或QGIS拉一个DEM数字高程模型确实能出立体效果但那只是“看得见”的视角想转成能进渲染器、能加材质、能放进游戏引擎的三维模型就非常别扭。后来换到Blender思路一下就通了Blender本质上是处理网格Mesh的工具而DEM就是一张带高程信息的灰度图每一个像素的亮度值代表海拔高度亮度越高地形越高。把这张图的亮度映射到网格顶点的Z轴位移上不就是现成的三维地形吗这个思路听起来简单但真正落地时牵扯到数据格式、精度、坐标、细分层级、材质贴图等一系列问题。网上关于“Blender DEM转三维模型”的教程不少但多数只讲到一半——要么只教你按几个按钮要么默认你已经有处理好的tif文件关键步骤全跳过。我把自己折腾了几天后跑通的全流程整理出来从数据准备到模型输出踩过的坑和优化点都会提到尽量让你照着做就能成功。这条流程适合谁如果你是在做游戏场景、建筑可视化、文旅数字孪生、影视预演或者单纯想把家乡某座山、某个水库的地形拉到三维世界里看效果那这篇文章应该能帮到你。不需要你有很强的编程能力懂一点Blender基础操作就行像细分、修改器、材质节点这些概念如果你完全陌生文中我也会顺带讲清楚。整个流程的核心链路是DEM数据准备 → 灰度图或插件导入 → 平面细分 → 根据高程图置换 → 网格清理与法线修复 → 材质和光照出效果。下面我按这条链路一步步展开中间会穿插一些我实际测试过的方法对比避免你走弯路。2. 数据准备tif文件里藏着的几个隐藏雷区2.1 DEM到底从哪来、选什么分辨率DEM数据的获取渠道很多常见的公开数据源包括SRTM30米/90米分辨率、ASTER GDEM30米、ALOS12.5米等国内的资源三号、高分系列也有部分开放数据。具体哪个网址能用网上随便一搜就有这个不是重点。重点在于你下载下来的tif文件往往不是“一块干净的土地”而是覆盖了很大范围比如一个整景数据可能包含几百公里。我的建议是先根据自己做模型的目标范围用GIS软件裁剪好再进Blender。拿QGIS举例加载tif后拉一个矩形框用“裁剪栅格”工具就能切出你关心的区域。这一步不做的后果是——你导入Blender后数据范围太大小范围内的高程细节被淹没置换出来的地形像一块扁平的豆腐啥也看不出来。而且大tif文件动辄几百MBBlender处理起来会卡到你怀疑人生。2.2 坐标系与范围裁剪比想象中更重要很多人在这一步栽跟头。DEM的原始坐标系通常是地理坐标系经纬度单位是度比如WGS84。如果直接把这样的tif丢进Blender会出现一个尴尬场面平面的长宽比极端悬殊纬度方向覆盖几度经度方向也覆盖几度但1度经纬度对应的实际地面距离在大多数纬度上不相等导致地形被严重拉伸变形。所以正式处理前建议先做一步投影转换。在QGIS里把DEM重投影到投影坐标系单位是米比如UTM带号对应的分区投影或者国内常用CGCS2000 / Gauss-Kruger。这样输出的tif每个像素对应的实际地面尺寸是均匀的进Blender后比例才正常。之前给一个工地做地形底图时忽略了这步结果模型的东西方向被拉长了将近一倍后来对照卫星图才发现白白重做了两遍。裁剪和重投影之后tif的尺寸也要注意。不需要导出最大分辨率按需重采样即可。我做游戏场景一般把地形控制在1024x1024或2048x2048像素做近景细节再多一点不要盲目用原始5000x5000的大图去置换Blender的细分和内存都会扛不住。2.3 tif到灰度图的格式转换别小看这一步Blender的置换修改器Displace可以直接读取tif图像但前提是它能正确处理这个文件。实际测试中某些多波段tifRGB合成或带透明度通道导入后Blender选择通道的逻辑会混乱出来的置换效果根本不是你想的那样可能是花屏一样的噪点。所以稳妥的做法是在QGIS或Photoshop里把DEM转成单波段的灰度图通常是16位或32位的浮点tif也可以导出为PNG但PNG只支持8位会丢失一部分高程精度适合预览不适合精细模型。如果你手头只有16位tifBlender也能读但要注意它默认按第一个通道处理。为了保证一致性我个人的习惯是用Python的GDAL库做一次格式归一化直接把tif转成8位灰度图或者16位单通道tif顺便把像素值线性拉伸到0到255或0到65535范围让地形的明暗层次拉满。这里贴一段我用过的Python代码一行行解释给你看from osgeo import gdal import numpy as np src_path raw_dem.tif out_path dem_gray.tif ds gdal.Open(src_path) band ds.GetRasterBand(1) arr band.ReadAsArray().astype(np.float32) # 将无效值NoData设为NaN避免参与拉伸 nodata band.GetNoDataValue() if nodata is not None: arr[arr nodata] np.nan # 根据实际高程范围做线性拉伸提升对比度 min_val np.nanpercentile(arr, 2) max_val np.nanpercentile(arr, 98) arr (arr - min_val) / (max_val - min_val) arr np.clip(arr, 0, 1) * 255 arr np.nan_to_num(arr).astype(np.uint8) driver gdal.GetDriverByName(GTiff) out_ds driver.Create(out_path, ds.RasterXSize, ds.RasterYSize, 1, gdal.GDT_Byte) out_ds.SetGeoTransform(ds.GetGeoTransform()) out_ds.SetProjection(ds.GetProjection()) out_ds.GetRasterBand(1).WriteArray(arr) out_ds.FlushCache()注意看我用np.nanpercentile而不是min/max是因为原始DEM偶尔会有异常高值用2%到98%的分位做拉伸能避免一两个异常像素把整张图的明暗对比毁掉。这一步处理完之后灰度图的层次感会肉眼可见地变好后续置换的地形细节也更多。3. 两条主要技术路线插件导入和Displace置换怎么选3.1 路线ABlender GIS插件直接导入如果你不想折腾灰度图就想快速把DEM变成一个可编辑的地形网格Blender GIS插件是最省事的路。安装好插件后在Blender的菜单栏会多出一个“GIS”选项选择File → Import → DEM选中你的tif文件插件会自动根据经纬度创建地形平面并按DEM的高程生成网格。它背后做的事情本质上就是把DEM的每个像素对应到网格顶点再用图像像素值驱动顶点高度。这个方案最大的好处是保留了真实的地理坐标信息你导入的地形范围、位置、尺寸都是对的后续如果还想叠加卫星影像图做纹理Blender GIS也提供了一项功能可以直接拉取在线影像图映射到地形表面。对大范围地景漫游项目来说这条路线效率很高。但它也有短板一是它对DEM的分辨率很敏感高分辨率大范围数据导入时生成网格的顶点数可能爆炸电脑配置不够会直接卡死二是它生成的网格是四边面为主的规则网格处理起来相对好办但如果你想做一些非规则的裁剪造型还得自己手动编辑。再就是它依赖在线服务器做某些数据和影像获取网络状况不好的时候不那么稳妥。3.2 路线BDisplace修改器置换Displace置换是Blender内置功能不依赖任何插件也是我今天重点讲的方法。它的核心逻辑是先新建一个平面给平面足够的细分然后添加Displace修改器在纹理设置里指定你处理好的DEM灰度图修改器就会自动把图像的亮度值映射到顶点Z轴上形成起伏地形。这条路线灵活度更高。你可以完全控制平面的网格密度、置换强度、偏移量可以随时在修改器里换贴图、调参数而且在应用修改器之前可以反复预览效果不满意就改不用重新导入。另外它不依赖在线服务任何环境都能跑更适合静下心来做精细控制。3.3 两条路线的核心区别对照我不是让你二选一而是建议按实际场景选。下面这张表是我实际使用后的体会对比维度Blender GIS插件导入Displace修改器置换坐标精度高保留真实经纬度/投影坐标低全凭手动缩放和平移操作复杂度低导入即可生成网格中需要自己处理细分和参数大范围支持较差网格数据量巨大时卡顿较好可控制网格密度叠加卫星图方便内置在线影像抓取手动映射UV后贴图精细控制一般高可随时调参数对原始数据要求直接读tif最好先转灰度预处理如果你只是快速看效果或做大致范围的地形底图用插件就好如果要做游戏关卡地形、需要精确控制网格、或者打算做低多边形风格化地形Displace绝对更顺手。我自己的习惯是前期用Displace快速搭出地形主形态再做二次编辑。4. 手把手实操用Displace生成地形的完整过程4.1 新建平面并调整比例基础不能错打开Blender新建一个平面默认大小2米x2米。这一步的关键是让平面的长宽比例和DEM图像的长宽比例保持一致。比如DEM灰度图是2000像素宽、1000像素高那平面就应该设置成20米x10米或者2米x1米否则地形会被横向压缩或拉伸。具体做法选中平面在右侧的“项目”面板里找到变换属性把X和Y的缩放数值改成和图像宽高比一致。我不推荐在导入图像后再改因为后面细分和置换都依赖这个比例越早定好越省事。实际操作中你先看一眼tif的像素尺寸用宽除以高得到一个比例系数再把平面X设为该系数、Y设为1保持等比例即可。4.2 细分平面为什么不能只靠默认平面新建的平面默认只有4个顶点如果不细分Displace修改器顶多让4个点上下移动那出来的是一块扭曲的纸板不是地形。细分的意思是把一个平面切成更小的网格每个网格顶点都能独立接收图像像素的亮度值网格越密地形细节越丰富。选中平面进入编辑模式右键选择细分Subdivide把切割次数增大。不过要特别注意细分次数和顶点数是呈指数增长的细分1次是2x2细分5次是32x321024个面细分8次是256x25665536个面细分10次是1024x1024约100万个面。100万个面对于刚才那台配置还不错的电脑来说已经接近流畅预览的上限了再高就会开始卡顿。我通常这样定次数先细分到总面数在30万到80万之间用来预览整体地形确认形态满意之后再进行更高细分局部区域可以单独用“细分”子工具加密。4.3 添加Displace修改器并加载纹理关键参数逐个讲选中平面在修改器属性面板里添加“置换Displace”修改器。这时会出现几个关键参数强度Strength控制整体地形起伏高度。默认值是1但实际DEM的高程范围通常有几百米你需要把这个值调大。比如你把1个Blender单位定为1米那么强度值就对应高程的缩放倍数。例如DEM高程覆盖范围是0到500米你可以先设强度为500再根据显示效果微调。需要提醒的是如果强度设置过大地形会穿模或者细节过曝建议先用较小的值预览。纹理Texture这里不是直接拖图片进Blender就行需要先创建一个图像纹理节点。点击修改器里的“新建”或“打开”找到你已经处理好的DEM灰度图载入。如果想更精确控制纹理映射可以到“着色器编辑器”里把图像纹理节点的坐标输出连到置换修改器上但大部分情况下直接在修改器里选图就够了。方向Direction默认Z轴这没问题。注意如果你的平面是垂直于地面的方向要改成法向Normal才能让置换沿着平面的朝向走。偏移量/中电平Midlevel这个参数控制灰度图的哪个亮度值作为基准面。默认值是0.5意思是亮度128中灰处对应零位移低于128向下凹陷高于128向上凸起。如果你把灰度图做了线性拉伸到0到255建议把中电平设为0这样亮度0对应零位移、255对应最高点地形高程和实际海拔的对应关系更直觉。设置完成后你可以在视口里看到地形雏形。选一张山地DEM测试效果应该是一眼能看出起伏而不是一片平坦。4.4 应用修改器什么时候“应用”最合适修改器的好处是非破坏性你可以随时调整参数而不用重建网格。但只要地形形态基本确定我建议及时应用修改器把置换结果固化到网格顶点上。原因有两点一是后续你很可能要配合布尔运算、雕刻、顶点绘制等操作这些工具不能作用于带有修改器的网格二是修改器在每次视口刷新时都会重新计算大网格下会拖慢操作流畅度。应用修改器的方法是选中带有Displace修改器的物体点击修改器右上角的下拉箭头选择“应用”。应用之后修改器消失但网格已经变成你看到的地形形状。记得在应用前确认参数已经调好因为应用后无法再通过修改器参数反悔。5. 网格清理与精度问题让地形不再“毛刺”和“穿帮”5.1 边缘处理如何让地形模型不再像一块空中飞地直接置换出来的地形边缘是垂直的“悬崖”还是自然的过渡实际上因为DEM覆盖范围的原因你的灰度图四周大概率是一片平面或突变高程。如果直接把这片平面作为最终模型侧面视角会穿帮特别是做3D打印或放进游戏引擎时边缘的垂直壁看起来非常假。处理方案有几类。最简单的是在四周加一圈向下的挤出Extrude做成一个底座或裙边。具体操作选中地形边缘一圈顶点按E键挤出并向下拉形成约半个地形高度的墙。这样模型俯视看是地形侧视看是实心体块比较符合人们常说的“地形模型”质感。做演示或3D打印底座时这个方法最常用。如果不想加墙也可以把边缘的顶点平均高度拉到一个基准面上形成缓坡过渡。做法是切换到顶点选择模式框选边缘圈用“平滑顶点”或者“缩放并压低到统一高度”的方式处理。两种方式的取舍在于用途游戏关卡地形通常选缓坡展示模型或打印常用裙边。5.2 法线问题为什么你的地形看起来坑坑洼洼置换之后的网格顶点位置变了但法线方向可能还是原始平面时的默认方向。如果直接进入渲染你会发现地形表面出现大量墨绿色或蓝色的斑块光照完全不正常。这个问题很好解决进入编辑模式全选顶点用“网格→法向→重算外侧”重置法线方向。如果你的地形是反的比如看起来像从地心向外看的凹陷感就再执行一次“翻转法向”。顺便说一句置换后的网格没有做平滑着色渲染出来的棱角感很强这是正常的。如果你想要平滑的表面选中文法线修复后的物体在“物体数据属性”里把着色方式改成“平滑着色”。还有一个小细节容易被人忽略置换后山脊部分会出现明显的阶梯状这是因为细分还不够密或者灰度图分辨率不足。如果不想增加细分可以试试给网格加一个“平滑修正”修改器不过谨慎使用它会把细节一起抹平有些得不偿失。5.3 坐标和尺寸从Blender单位换算到真实米Blender默认单位是米但平面尺寸和置换强度设置完之后模型的实际尺寸可能并不是你想要的。比如灰度图覆盖的范围是3公里x2公里你却希望模型整体在Blender里只有10厘米大小比如做小比例模型摆件这就要注意整体缩放关系了。我的习惯是先确定输出目标。做游戏地形时把Blender单位直接对应为米模型尺寸设成真实地面尺寸方便后续与引擎单位对齐。做展示模型或3D打印时先算出真实范围再按比例缩放。有个小技巧选中地形物体查看网格属性里的尺寸信息按你需要的目标尺寸做整体缩放缩放后注意法线和变换应用CtrlA → 应用缩放否则后续的雕刻或贴图会出现奇怪的比例扭曲。6. 实操中容易忽略但影响巨大的几个细节6.1 灰度图的明暗范围影响地形起伏的层次感很多新手拿一张原始DEM直接丢进Blender结果置换出来的地形“平平的”然后就以为是强度不够猛加Strength。其实问题往往出在灰度图的对比度上。原始DEM的高程数据分布往往比较集中比如一座山从海拔200米到海拔800米如果直接线性映射大部分像素的亮度落在30到120之间对比度拉不开。经过分位拉伸处理之后暗部更暗、亮部更亮地形细节才能真正显现出来。上面那段Python代码中我用的是2%到98%分位拉伸实际操作中你可以根据效果动态调整分位数。如果发现城市平原区域细节不足就把分位区间适当收窄比如改成5%到95%平原的微小起伏会更容易看清楚。这个方法对低起伏地区的效果尤其明显值得多试几次。6.2 细分密度不是越大越好如何平衡细节和流畅度我见过有人为了追求细节直接把平面细分到2000x2000也就是400万个面然后Blender直接卡死最后只能强制关闭。做地形不是像素越高越好而是要根据用途找到合适的密度。我的经验公式大致是预览阶段不超过100万面最终输出给游戏引擎的模型不超过30万面给渲染器出静帧可以放宽到200万面。如果你确实需要超高细节更好的做法是局部加密而不是全图均匀细分。选中需要更多细节的区域进入编辑模式用“边线细分”工具只分割选中区域能明显减少总面数。6.3 置换后顶点位置偏移为什么有些地形高出天际如果你的灰度图带有背景值或NoData值被填充成了0那么这些区域会被置换到地表以下呈现出一个大坑。而如果NoData被填充成255就会变成突兀的高山尖刺。处理方式是在前面数据准备环节里把NoData区域统一处理成一个和有效数据最低值相近的值或者干脆裁掉这些区域。另一个容易踩的坑是灰度图的尺寸和细分后的网格数量不一致。比如图像是1024x1024像素而平面细分只有256x256个顶点那置换时Blender会采样图像插值细节损失严重。反之如果你细分了1024x1024个顶点但图像只有512x512多出来的顶点只能从已有像素插值不会增加更多细节。所以图像分辨率和网格密度要大致匹配。7. 让地形“活”起来的进阶技巧材质贴图与光照配置7.1 给地形赋材质从灰度到彩色的跨越刚置换出来的地形是灰白的真实感远不够。要让它像真实地表最直接的办法是叠加卫星影像图。处理方法分两步第一步把卫星影像图也是tif或jpg作为纹理贴图通过UV映射平铺到地形表面第二步在材质节点里将影像和地形法向结合。关键在于UV。置换出来的地形需要先做一次“智能UV投射”或“柱面/平面投射”让影像贴合地形表面。我通常选择“智能UV投射”Smart UV Project因为它在不规则地形上的效果最稳基本不会出现接缝过大的情况。投射之后在“着色器编辑器”里新建一个“图像纹理”节点载入卫星图连接到“基础色”输入上。一个能看的地形材质就完成了。如果你想手动控制贴图区域可以进入编辑模式用UV编辑器调整顶点在影像中的位置这适合应用在高精度的局部重点区域不是全图一张贴图时。7.2 程序化材质没有卫星图时也能做风格化地形拿不到免费卫星图或影像图分辨率太低时用程序化纹理也能做出效果不错的地形。Blender内置了各种程序化噪波纹理可以模拟岩石、草地和雪线的混合。用“颜色渐变”节点把高度信息来自置换前的高程数据或Height输出映射到不同颜色实现山脚翠绿、山腰土黄、山顶雪白的分层效果。具体节点连接逻辑是获取地形高度可以用“纹理坐标→物体→分离XYZ”的Z值经过“映射范围”节点归一化再连到“颜色渐变”节点的系数输入。颜色渐变里设置多个颜色停靠点低处深绿、中段褐色、高处淡灰白色出来的地形一下子就有了海拔带的感觉。这个方案对风格化场景特别友好而且不需要外部图片。7.3 光照地形模型成功的另一半很多新手做完地形发现灰蒙蒙的第一反应是材质问题其实是光照没跟上。Blender默认的灯光是一个比较平的场景灯你需要主动建立一个太阳光Sun light并调整角度让地形产生明暗面才能看出山体的起伏轮廓。我常用的布光方式一个主太阳光强度1到3角度从侧上方30度到45度照过来一个补光强度0.5左右从相反方向补暗部细节再加一个环境光World的强度根据天气氛围调。太阳光的阴影软硬可以通过“光尺寸”Light Size调整光尺寸越小阴影越锐利适合表现细节丰富的地形。渲染器方面Eevee预览速度快但地面阴影容易漂浮Cycles渲染真实感强但大场景会比较慢。我通常先用Eevee调好材质和灯光氛围最后切换Cycles出成品图。这个组合策略效率更高。7.4 地形的导出给其他软件用的注意事项做完地形后你需要把它导出成通用格式。如果是给游戏引擎用FBX和OBJ都常用但要注意导出的单位、坐标轴向、法线方向。引擎坐标轴通常是Y轴或Z轴向上而Blender默认Z轴向上多数引擎也是Z轴向上对得上。导出前面板里要勾选“应用变换”和“三角化网格”避免引擎里出现奇怪的斜边。如果需要和GIS数据进一步配合可以导出带坐标信息的格式但Blender原生导出不支持地理坐标通常的做法是你在Blender里先把模型摆正再进行缩放和平移确保和你的场景基准对齐。8. 最后再分享一些我个人的使用习惯折腾了这么多地形项目我现在的基本流程是先在QGIS里把DEM裁好、转好灰度图同时导出一份卫星图备用然后打开Blender做置换先低细分快速定形态再高细分做细节材质上优先用卫星图不够再补程序化纹理灯光永远用太阳光加补光的组合。这套流程看着步骤多但每一步都不复杂习惯了之后半小时内就能出一个像样的地形效果。有一个建议特别想给你不要一开始就追求超大范围的DEM导入先做一个小范围、高精度的局部把整条流程熟一遍再往上加范围。我第一次直接拿一个10公里范围的数据导入结果光细分就花了十分钟还不停崩最后放弃了。从小处着手反而更快理解这套流程的核心。另外如果你后续有动画需求比如摄像机绕山飞一圈记得地形面数控制在百万以内否则Cinematic效果出不来。大范围地形想要流畅可以考虑把一块大地形拆成多块小地形分别置换和管理性能会好很多。