news 2026/2/18 4:21:17

从 DEM 到 3D 渲染:R 语言 rayshader 地形可视化全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 DEM 到 3D 渲染:R 语言 rayshader 地形可视化全指南

一、为什么要用 rayshader?

当我们打开一张普通的地图时,看到的往往是平面的线条和色块。虽然我们可以通过等高线去想象山脉的起伏,或者通过蓝色的深浅去猜测湖泊的深浅,但这始终缺乏一种身临其境的震撼感。rayshader 的出现,就是为了打破二维平面与三维世界之间的那堵墙。 它不仅仅是一个绘图工具,更像是一位精通光影艺术的数字雕刻家。它能将那些枯燥的地理高程数据,转变为栩栩如生的微缩景观。

rayshader 最大的价值在于化繁为简,它依托于 R 语言,将极其复杂的 3D 渲染流程封装成了极简的指令。你不需要懂得如何计算光线的折射角度,也不需要手动去构建每一个山峰的模型,你只需要告诉它:“这里是数据,给我加上早晨 8 点的阳光”,它就能自动帮你完成剩下所有的任务。而且,rayshader 最迷人的地方在于它对真实感的追求。普通的 3D 地图往往看起来像是由塑料堆砌而成的玩具,缺乏质感。而 rayshader 引入了光线追踪与环境光遮蔽技术,它能精确模拟阳光是如何洒在山脊上的,云层的阴影是如何投射在深谷中的,甚至能模拟出大气层的雾气感和水面的波光粼粼。这种对光影的细腻处理,能让一张普通的地形图瞬间拥有艺术摄影般的质感。因此,其特别适合在GIS相关工作中应用。

二、数据读取与转换

首先打开RStudio,从开始菜单中或桌面快捷方式打开都可以:

图1 找到RStudio并打开

我们以示例数据集为例,将附件的数据集名字重命名为satellite_image.csv,然后将其粘贴到R的工作目录内。由于目前我们并不知道工作目录在哪,因此需要现在R studio中输入代码进行寻找:

getwd()

输入后,便能够得到返回结果,找到当前的工作目录:

图2 返回的工作目录

将获得的地址粘贴到此电脑的地址栏中,回车进入:

图3 粘贴到地址栏回车进入目录

将示例数据集改名并粘贴到这一目录:

图4 改名并粘贴

rayshader 并不直接分析 TIF 文件,它需要矩阵数据。因此,我们需要在 RStudio 中复制并粘贴运行以下代码:

# 0. 安装工具包 install.packages(c("rayshader", "terra")) # 1. 加载必要的工具包 library(rayshader) library(terra) # 2. 读取您的本地数据文件 # 这里我们使用 terra 包的 rast() 函数,就像把文件从硬盘里“拿”出来 # 注意:请确保 'satellite_image.tif' 文件在您的当前工作目录下,或者填写完整路径 tif_data <- rast("satellite_image.tif") # 3. 关键步骤:将地理文件转换为 rayshader 能识别的“矩阵” # rayshader 提供了一个贴心的函数 raster_to_matrix,专门负责这个翻译工作 elmat <- raster_to_matrix(tif_data) # 4. 检查一下是否成功 # 我们看看这个“表格”的大小 dim(elmat)

运行代码后,可以看到已经输出了结果:

图5 输出的检查结果

三、第一次 3D 渲染

数据准备好了,现在我们开始生成模型。rayshader制作 3D 地形就像是搭建积木,但我们不需要一块一块去搭,只需要两步简单的指令:先给它上色,再把它拉起。在 R 语言中,我们经常使用一个像管道一样的符号 %>%。可以把它想象成工厂里的传送带:数据从左边进去,经过加工后,传给下一个环节。这样写代码,就像在读句子一样自然。复制并粘贴运行以下代码:

# 这里的 elmat 是我们在上一节生成的矩阵数据 elmat %>% height_shade() %>% # 第一步:根据高度生成基础颜色(皮肤) plot_3d( # 第二步:根据矩阵数值构建 3D 模型(骨架) elmat, # 告诉它用哪个数据来决定山的高度 zscale = 30, # 【关键参数】海拔缩放比例(详见下文解读) fov = 0, # 摄像机视野,0 代表正交视图(像地图),70 代表透视(像人眼) theta = 45, # 摄像机的水平旋转角度(0-360度) phi = 45, # 摄像机的俯视角度(0-90度,90是垂直俯视,0是平视) windowsize = c(1000, 800), # 弹出的 3D 窗口大小 zoom = 0.7 # 初始缩放级别 )

代码中,height_shade() 代表根据高度给地图上色。低的地方涂上代表水的蓝色或平原的绿色,高的地方涂上代表山峰的白色或褐色。这相当于给模型穿了一层基础的皮肤。plot_3d() 则是 rayshader 的重要函数。它会根据我们之前的 elmat 高度矩阵,把平面的颜色“顶”起来,形成 3D 实体。

生成的结果如下图:

图6 生成的3D结果

按住鼠标左键拖动可以旋转模型,从东南西北各个角度观察山脉。按住鼠标右键拖动可以拉近或推远,像无人机一样俯冲进山谷,或者飞到高空概览全貌。按住鼠标中键拖动则是平移视图。虽然现在的地形看起来还比较简单,只有颜色过渡,但它已经是一个真正的三维实体了。接下来我们通过叠加图层和光影处理,让它变得像照片一样真实。

四、叠加图层:给地形穿衣服

如果说 plot_3d 是构建骨架,那么这一步就是给骨架穿上衣服。在专业的地图绘制中,我们很少只用一种颜色。通常,我们会把“光照质感”和“海拔颜色”混合在一起,甚至如果有卫星照片,也可以直接贴在模型表面。rayshader 强大的地方在于它允许我们像 Photoshop 一样,一层一层地叠加图片。

在上一节我们用了 height_shade(按高度上色)。现在我们使用更高级的函数:sphere_shade()。它会模拟光源照射在起伏地面上的效果,生成一张带有明暗阴影的“浮雕图”。这会让地形即使在平面状态下,看起来也有立体的质感。这个函数的搭配按照以下方式进行:

1.底图:使用 sphere_shade 生成的黑白浮雕,提供纹理细节。

2.覆盖层:使用 height_shade 生成的彩色高度图,提供直观的海拔信息。

3.混合:使用 add_overlay 将两者融合,类似给照片上色。

复制并粘贴运行以下代码:

install.packages("magick") # 1. 加载必要的库 library(rayshader) library(terra) library(magick) # 【关键】加载图像处理包,解决报错问题 # 2. 制作“内衣”:基于光照的黑白浮雕层 base_layer <- sphere_shade(elmat, texture = "bw", sunangle = 45) # 3. 制作“外套”:基于高度的彩色层 color_layer <- height_shade(elmat, texture = terrain.colors(256)) # 4. 穿衣并渲染 elmat %>% sphere_shade(texture = "bw", sunangle = 45) %>% add_overlay(color_layer, alphalayer = 0.6) %>% # 现在有了 magick,这一步就能成功了 plot_3d( elmat, zscale = 30, fov = 0, theta = 45, phi = 45, windowsize = c(1000, 800), zoom = 0.7 )

可以看到,结果已经被自动生成:

图7 生成的结果

现在,3D 地形图既有丰富的颜色,又有清晰的山体脉络。接下来,我们用阴影让它变得更加深邃。

五、添加阴影层

在现实世界中,光线不仅仅是直射的。在一个深邃的山谷底部,即使阳光没有直接照进去,也会因为周围山壁的遮挡而显得比较暗;而在开阔的山顶,光线则非常充足。这种“因为周围物体遮挡而产生的阴影”,在计算机图形学中叫做环境光遮蔽。

如果不加这一层,生成的山脉就像是用塑料做的,每个角落都很亮;加上这一层,山脉的皱褶感、深邃感会得以显现,就像给素描画加上了重重的阴影线条。

我们需要用到两个生成阴影的函数:

1.ray_shade():模拟太阳光产生的直接投影(比如山峰挡住了背后的光)。

2.ambient_shade():模拟环境光遮蔽(比如山谷缝隙里的暗部)。

接下来,我们将底色 + 太阳阴影 + 环境阴影叠在一起。复制并粘贴运行以下代码:

# 1. 计算太阳光阴影(Ray Shade) # 模拟太阳从西北方向(sunangle = 315)照射产生的硬阴影 # zscale = 30 必须与 plot_3d 中的一致,否则阴影位置会跑偏 ray_shadow <- ray_shade(elmat, sunangle = 315, zscale = 30) # 2. 计算环境光遮蔽(Ambient Shade) # 模拟山谷缝隙里的软阴影,这会让地形看起来更深邃 amb_shadow <- ambient_shade(elmat, zscale = 30) # 3. 混合所有图层并渲染 elmat %>% sphere_shade(texture = "bw", sunangle = 315) %>% # 底层:黑白光照 add_overlay(color_layer, alphalayer = 0.6) %>% # 中层:彩色高度(上一节做的) add_shadow(ray_shadow, max_darken = 0.5) %>% # 顶层1:叠加太阳阴影 add_shadow(amb_shadow, max_darken = 0.5) %>% # 顶层2:叠加环境阴影 plot_3d( elmat, zscale = 30, fov = 0, theta = 45, phi = 45, windowsize = c(1000, 800), zoom = 0.7

运行这段代码后,能够发现山谷的深处和山脊的背光面质感变得厚重了。这种充满电影质感的画面,就是光影魔法的魅力。接下来,我们进一步开启光线追踪,模拟真实的大气和光线反弹。

六、开启光线追踪

到目前为止,我们在 RGL 弹出窗口中看到的 3D 地形,只是一个实时预览版。为了保证拖动鼠标时画面流畅,电脑省略了很多复杂的光影计算。现在,我们要使用 render_highquality() 函数,启动光线追踪技术,计算每一束光线在山谷间的反射、折射和散射。

运行这段代码前,必须保持之前的预览 3D 窗口(RGL窗口)处于打开状态,并调整好最佳角度。运行代码后,R 会开始计算,可能需要几十秒,具体取决于电脑性能。复制并粘贴运行以下代码:

#这里的参数不再是控制模型,而是控制“摄影棚”的灯光和相机 render_highquality( lightdirection = 315, # 阳光照射的方向(西北方) lightaltitude = 45, # 阳光的高度(45度角,类似上午9点的太阳) lightintensity = 800, # 阳光的强度 samples = 200, # 【关键】采样数:数值越高,噪点越少,画质越细腻,但速度越慢 clear = TRUE # 渲染完成后,自动关闭那个 3D 预览窗口以释放内存 )

生成的结果如下所示:

图8 完成渲染的图出现在右下角

观察结果可以发现,阴影不再是完全黑暗,而是带有柔和的过渡(软阴影);原本生硬的棱角,现在被光线包裹得更加自然。这一步生成的图片,已经具备了作为壁纸或海报的潜质。但如果想让它看起来更像微距摄影作品,我们还可以加上最后一道滤镜——景深与虚化。

七、景深与虚化

在 rayshader 中,实现景深与虚化效果不需要昂贵的相机镜头,只需要调整一个参数:光圈。光圈越大,背景虚化越强烈。在 render_highquality() 函数中,我们只需要加入 aperture 参数:

1.aperture = 0:默认值。全图清晰,没有虚化(像手机拍风景)。

2.aperture = 10 到 30:适合地形图。会让远处和近处的山峰模糊,焦点集中在画面中心,产生强烈的微缩模型感。

复制并运行以下代码:

# --- 第一步:重新构建 3D 窗口--- # 这一步和之前一样,只是为了确保有一个东西可以被拍摄 elmat %>% sphere_shade(texture = "bw", sunangle = 315) %>% add_overlay(color_layer, alphalayer = 0.6) %>% add_shadow(ray_shadow, max_darken = 0.5) %>% add_shadow(amb_shadow, max_darken = 0.5) %>% plot_3d( elmat, zscale = 30, fov = 0, theta = 45, phi = 45, windowsize = c(1000, 800), zoom = 0.7 ) # --- 第二步:带景深的“微缩摄影” --- render_highquality( lightdirection = 315, lightaltitude = 45, lightintensity = 800, samples = 200, # 【新增核心参数】 aperture = 30, # 光圈大小。数值越大,虚化越强。建议尝试 10-50。 # 焦点位置:默认情况下,rayshader 会自动对焦在模型中心。 clear = TRUE # 渲染完关闭窗口 )

完成渲染后的效果如图所示:

图9加入景深与虚化后的效果

观察图片可以发现,画面中的山峰具有了清晰锐利的效果,画面边缘则呈现出了朦胧的模糊感。这种虚化效果能有效消除计算机生成的生硬感,让地形图看起来就像是专业插图。现在,我们已经完成了一幅作品,最后一步就是把它保存下来。

八、导出与分享

rayshader 提供了专门的函数,能以原始分辨率保存作品,确保每一个像素都清晰可见。如果刚刚运行完光线追踪渲染,图片显示在 Plots 面板里,则需要在 RStudio 右下角的 Plots 面板上方,点击右键,然后选择"Save Image as":

图10 右键并保存

随后,选择保存目录,点击 Save 即可完成保存:

图11 选择保存目录

另外,我们还可以生成一段航拍视角的旋转视频。复制并粘贴运行以下代码:

install.packages("av") library(av) library(rayshader) # 1. 确保 3D 窗口是打开的 # (如果之前关闭了,请重新运行一遍 plot_3d 的代码块) # 2. 生成旋转动画 # theta: 摄像机旋转的角度范围(0到360度) # phi: 摄像机的俯视角度(保持30度俯视) render_movie(filename = "mountain_flyover.mp4", type = "oscillate", frames = 360, # 总帧数,帧数越多视频越流畅 phi = 30, zoom = 0.6, title_text = "3D Terrain Flyover")

完成渲染后,视频的保存位置会显示在输出结果中:

图12 视频的保存位置

播放的效果如图所示:

图13 视频的播放效果

至此,我们完整走完了从一张 DEM 数据,到生成 3D 地形图的全过程,可以在实际研究或生产中进行应用了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/16 10:21:47

写了一套几乎无敌的参数校验组件!!!

参数校验这个东西&#xff0c;很多情况下都是比较简单的&#xff0c;用 NotNull、Size 等注解就可以解决绝大多数场景&#xff0c;但也有一些场景是这些基本注解解决不了的&#xff0c;只能用一些其他的方式处理&#xff0c;这样就导致参数校验变成了多层&#xff0c;其实是不利…

作者头像 李华
网站建设 2026/2/14 13:28:08

纺织设备远程监控运维管理平台方案

在纺织行业蓬勃发展的今天&#xff0c;纺织机械作为生产线的核心装备&#xff0c;其稳定运行直接关系到生产效率和产品质量。然而&#xff0c;随着纺织企业规模的扩大和设备的多样化&#xff0c;传统运维方式已难以满足现代纺织生产的需求。该平台通过高度兼容的技术架构&#…

作者头像 李华
网站建设 2026/2/10 16:29:56

DeepSeek-R1一周年回顾与MODEL1新模型技术前瞻

文章回顾了DeepSeek-R1发布一周年的意义&#xff0c;并分析了代码库中出现的MODEL1可能代表的新一代推理模型(R2或全新产品线)。文章探讨了R1如何通过开源策略改变AI推理生态&#xff0c;使模型从"黑箱"变为"白盒"&#xff0c;从结果导向转向过程导向。MOD…

作者头像 李华
网站建设 2026/2/17 6:25:32

<span class=“js_title_inner“>智筑安全防线慧享畅行民生——公安交管部门以科技创新书写新时代答卷</span>

从云端的数据之眼到路面的智慧之治&#xff0c;从指尖的便民服务到城市交通的“绿波”畅行&#xff0c;科技的力量正以前所未有的深度和广度&#xff0c;重塑着道路交通管理的方方面面。近年来&#xff0c;全国公安交通管理部门坚持以人民为中心的发展思想&#xff0c;深入实施…

作者头像 李华