约 21 分钟技术学习游戏引擎

Games104学习笔记(6)

GAMES104:游戏中地形、大气和云的渲染(上)

第 6 讲(上)|本段重点:大规模地形渲染与内容整合
视频时长:约 1 小时 16 分 36 秒
说明:本文根据本地视频的课件与讲解脉络整理,不是逐字稿。 这一节依旧基本听不懂。

一句话理解

大型游戏地形的难点不只是“画一张高度图”,而是要在超大尺度、近景细节、稳定的 LOD、材质多样性、流式资源与编辑能力之间做系统级取舍。课程给出的路线是:用自适应网格管理几何密度,用 GPU 管线提高细节生成效率,用虚拟纹理解决材质数据规模,并用相机相对渲染和装饰物/道路系统把地形接入完整世界。

本讲学习目标

  • 区分高度场、三角网格、四叉树与体素地形的表示能力和代价。
  • 理解地形 LOD 为什么会产生 T-Junction、裂缝和过渡问题。
  • 了解 GPU Tessellation、Mesh Shader、Marching Cubes 在地形中的角色。
  • 说明 Texture Splatting 为什么会在大世界中遭遇纹理数量与显存瓶颈。
  • 掌握虚拟纹理的 virtual texture、page table、physical texture 三层思路。
  • 知道相机相对渲染如何缓解超大世界的浮点精度问题。
  • 建立“地形几何、材质、流式、装饰物和编辑工具必须协同设计”的认识。

1. 为什么自然场景是渲染系统的压力测试

自然场景同时具有几类互相冲突的需求:

  • 尺度大:远山、地平线、道路网络与开放世界地表都要求很大覆盖范围。
  • 近景细节多:岩石、泥土、草地、水沟和道路边缘需要足够的几何与材质细节。
  • 视点变化剧烈:玩家高速移动、飞行或切换视角,LOD 不能明显跳变或出现裂缝。
  • 内容要可编辑:关卡人员需要绘制地貌、道路、地表材质、植被和局部标记。
  • 资源预算有限:地形可能覆盖数十到数百平方千米,但内存、显存和每帧带宽有限。

所以地形渲染更像一个“内容生产 + 资源调度 + 图形算法”的联合系统,而不是孤立的 Vertex Shader 技巧。

2. 高度场:简洁但能力受限的地形表示

2.1 Heightfield 的基本模型

高度场把地形写成二维位置上的单值高度:

$y = h(x,z)$

在规则网格上,每个格点保存一个高度值,再由相邻格点组成三角形。它天然适合山地、丘陵、平原等“从上方观察能投影到平面”的地形。

2.2 高度场的优点

  • 数据布局规则,便于存储、采样和 GPU 并行处理。
  • 高度图可视作纹理,编辑工具和生成算法容易接入。
  • 碰撞、植被分布、法线计算、地表混合等功能较容易建立在规则坐标系上。
  • 对远景而言,规则网格配合 LOD 的实现成本较低。

2.3 高度场做不到什么

由于每个 (x, z) 只有一个高度,普通高度场难以自然表达:

  • 悬崖下方的掏空区域;
  • 山洞、隧道、拱门;
  • 同一水平位置的多层地表;
  • 可被挖开的复杂体积地形。

因此,选择高度场意味着以表达力交换效率。开放世界中的大面积地表通常很适合它,但洞穴等局部结构常需要独立网格、体素数据或混合方案补足。

3. 地形 LOD:把三角形花在看得见的地方

3.1 视点相关误差是 LOD 的判断依据

课件提出视点相关的优化原则:LOD 不应只按世界距离粗暴切换,而应关注近似误差在屏幕上是否可见。影响因素包括:

  • 相机与地形块的距离;
  • 视场角与屏幕分辨率;
  • 地形在当前投影下的屏幕尺寸;
  • 地貌变化强度,例如平坦区域与尖锐山脊对网格密度的需求不同。

一个实用目标是:远处误差在屏幕上小到难以察觉,就不值得为它保留近景级别的三角形数量。

3.2 自适应网格细分

自适应细分会让近处或地形变化剧烈的区域使用更密集的三角形,远处或平坦区域使用更粗的网格。这样能显著降低总体三角形数,但也立刻引入邻接块不同细分层级的连接问题。

3.3 T-Junction 与裂缝

当一个细分较密的边与一个较粗的边相接时,细网格的顶点可能落在粗网格边的中间,而粗网格并没有对应顶点。这就是 T-Junction。

若不处理,两个块在光栅化和位移后可能出现细缝、漏光或不连续的轮廓。地形 LOD 的关键并非只会“切得更细”,而是要保证相邻区域的拓扑关系可衔接。

3.4 连续性策略

常见处理思路包括:

  • 约束相邻块的 LOD 等级差,避免差距过大。
  • 为边界准备 stitching(缝合)三角形或索引模式。
  • 让细分模式满足可拼接的规则。
  • 采用带过渡带的形变或几何混合,减少视觉突变。

这些策略都体现了一个事实:地形 LOD 是一张邻接关系图上的全局协调问题,不是每个块各自独立的决策。

4. 三角形、四叉树与不规则三角网

4.1 三角形细分

三角形是 GPU 最基本的图元。以三角形为单位细分,适合不规则地貌和局部误差控制,但邻接关系、边界缝合与索引管理更复杂。

4.2 QuadTree-Based Subdivision

四叉树把地表区域递归分成四个子块。它的主要优点是:

  • 层级结构直观,容易构造与管理。
  • 适合规则网格和块级流式加载。
  • 容易按相机距离做粗粒度裁剪与 LOD 选择。

但四叉树块之间仍要处理不同 LOD 的边界;对于非常不规则的地貌,单纯规则划分的几何效率可能不如更自由的三角网。

4.3 TIN:Triangulated Irregular Network

不规则三角网(TIN)可在地形变化大的地方放更多顶点,在平坦区域放更少顶点。它的优势是几何密度更贴合误差分布;代价是构建、更新、邻接查询、流式和 GPU 数据组织都更复杂。

可以这样概括三者:

表示/划分 强项 主要代价
规则高度网格 实现简单、纹理化友好 容易在平坦区域浪费顶点,难表达洞穴
四叉树块 LOD、裁剪、流式管理清晰 需要处理块边界与层级过渡
TIN 几何密度更贴合地貌 数据结构和邻接管理复杂

5. 让 GPU 参与生成地形细节

5.1 GPU Tessellation

硬件 Tessellation 管线通常包括 Hull Shader、Tessellator、Domain Shader 等阶段。它允许用较粗的控制网格作为输入,再根据距离、曲率或误差在 GPU 上生成更多三角形。

地形中常见的组合是:

  1. CPU 或前序阶段提供粗网格块。
  2. Tessellation 根据视点设定细分因子。
  3. Domain Shader 采样高度图或位移图,生成最终顶点位置。

这让“细节生成”更靠近 GPU,但不能消除细分过度、块边界不一致、位移后裂缝等问题。

5.2 Displacement Mapping 与细分

位移贴图真正改变顶点位置,能够产生轮廓变化;但若基础网格不够密,位移仍然只能看到粗糙台阶。因此它通常与 Tessellation 或足够高密度的几何配合。

不要把它与 Normal Mapping 混淆:法线贴图主要改变光照法线,不会改变物体轮廓,也无法让地形真的“凸起来”。

5.3 Mesh Shader Pipeline

课件还介绍了 Mesh Shader Pipeline:

  • Amplification/Task 阶段可以决定如何组织工作组、筛选或放大任务。
  • Mesh Shader 阶段直接输出一小簇顶点和图元。

相比传统固定的几何处理链,Mesh Shader 给引擎更多机会把小块几何生成、可见性筛选和数据布局放到 GPU 上协同完成。它适合现代 GPU 架构,但需要面向目标硬件设计回退路径与资源组织方式。

6. 当高度场不够用:洞穴与体积地形

6.1 挖洞为什么困难

高度场只能表示单层表面,因此“在地面挖洞”会破坏其单值函数假设。单独放置洞穴网格可以解决很多游戏需求,但地表与洞口的连接、材质过渡、碰撞和编辑工作流仍需额外设计。

6.2 体素表示

体素把三维空间离散成格子,每个格子可存密度、材质或符号距离等数据。它能够表示洞穴、悬空岩石和任意拓扑变化,因此适合可破坏地形或程序化地形。

相应代价是:

  • 三维数据量远大于二维高度图。
  • 需要从体数据提取可渲染表面。
  • 编辑、存储、流式与碰撞都更昂贵。

6.3 Marching Cubes

Marching Cubes 通过检查每个体素单元角点的内外状态,选择相应的三角形配置来近似等值面。它是体素地形“从密度场变成三角网格”的经典步骤。

需要注意:Marching Cubes 解决的是表面提取,不自动解决大世界的分块边界、网格更新、LOD、纹理坐标和资源调度;这些仍是引擎系统问题。

7. 地形材质:从贴图混合到可扩展的层系统

7.1 Texture Splatting 的出发点

地形通常需要草地、泥土、碎石、岩石、积雪等多种材料。Texture Splatting 的基本做法是:

  • 采样多个材质纹理;
  • 用权重图/控制图决定每种材质的比例;
  • 将各材质的颜色、法线、粗糙度等属性混合。

它非常直观,适合编辑器中的“刷地表材质”。

7.2 简单混合为什么容易显得不自然

如果仅用平滑权重做线性混合,岩石与草地会像被均匀揉在一起,缺少材料之间应有的覆盖关系和形态逻辑。课程随后给出更高级的做法:引入高度、坡度、噪声或材质优先级,形成带偏置的混合。

7.3 Height-Based Blending

高度混合利用各材质自身的高度信息或局部结构,让“更突出的颗粒/岩石”在过渡区保留形状,而不是被平滑平均掉。它通常更自然,但需要额外纹理数据与更复杂的采样、比较和归一化操作。

7.4 Material Texture Array

多个同规格材质纹理可放入 Texture Array,以层索引选择不同材料。它有助于统一采样接口、减少资源绑定复杂度,并适合材质层数量明确、纹理尺寸和格式统一的场景。

7.5 Parallax 与 Displacement 的取舍

对地表近景,课程对比了颜色贴图、凹凸/法线、Parallax Mapping 和 Displacement Mapping:

  • Parallax Mapping 主要在像素阶段扰动纹理坐标,制造视差感,不改变真实几何轮廓。
  • Displacement Mapping 改变几何位置,能提供真实轮廓,但需要网格细分和更多几何成本。

它们的选择取决于玩家距离、边缘轮廓是否可见、GPU 预算和内容复杂度。

8. 材质混合的规模瓶颈

8.1 多材质意味着多次纹理读取

每多一个参与混合的材质,通常就会增加 Base Color、Normal、Mask 等纹理读取。若一个地形像素需要混合很多层,带宽和像素着色成本会迅速上升。

8.2 巨型 Splat Map 的问题

把整个超大世界的材质权重全部放进一张或多张巨大控制图,看似直接,实际会带来:

  • 视频内存中只需要场景的一小部分,但巨大贴图难以整体常驻。
  • 高分辨率世界需要很多 mip 层与存储空间。
  • 远处与近处对材质数据精度的需求不同,统一加载会浪费带宽。
  • 编辑数据和运行时采样数据的理想格式未必相同。

这正是虚拟纹理要解决的问题。

9. 虚拟纹理:用地址空间管理巨大的地表材质

9.1 核心思想

虚拟纹理不要求把整张超大纹理完整放入显存。它把逻辑上巨大的纹理切成固定大小的 tile/page:

  • Virtual Texture:逻辑地址空间,代表整个世界的材质结果。
  • Page Table:将虚拟页映射到当前驻留的物理页。
  • Physical Texture Cache:显存中真正存放已加载 tile 的有限缓存。

Shader 采样时先查询页表,再从物理缓存取对应 tile。不可见或低优先级区域可以不驻留,真正需要时再流入。

9.2 地形中的典型用法

课程列出的思路可以概括为:

  1. 在逻辑上为整个场景建立可索引的巨大地表材质空间。
  2. 按视点相关 LOD,只加载当前可见区域需要的 tile 数据。
  3. 将多层材质混合的结果预烘焙到 tile,并把结果放到物理纹理缓存中。

运行时由“每像素混合很多原始材质”,转为“多数情况下采样已生成的地表 tile”。这就是以离线/后台处理和流式调度,换取稳定的帧内着色成本。

9.3 虚拟纹理不是免费的

它引入了新的工程问题:

  • 页缺失时如何反馈和调度。
  • 快速移动时如何避免 tile pop-in。
  • page table 更新与缓存替换如何保持正确。
  • 不同 mip、边界过滤和 tile border 如何避免接缝。
  • 编辑后哪些 tile 需要失效、重烘焙和重新上传。

因此,虚拟纹理的价值在于控制规模,而不是省去资源管理。

9.4 DirectStorage 与 DMA 的启发

课件还把虚拟纹理与 DirectStorage、DMA 放在同一脉络中:当存储设备、主存、显存和 GPU 的数据路径更高效时,地形 tile 的流式传输可以减少 CPU 参与和中间拷贝。对引擎设计而言,关键是把资源格式、IO 调度、解压位置和 GPU 上传路径当作一条完整管线来考虑。

10. 超大世界的精度:Camera-Relative Rendering

10.1 浮点精度为什么会出问题

单精度浮点数的可表示间隔会随数值绝对值增大而变粗。当相机和物体的世界坐标达到很大数量级时,细小的位置变化可能无法准确表示,表现为抖动、表面闪烁、物体边缘不稳定等。

10.2 以相机为局部原点

相机相对渲染的做法是:在送入图形变换前,用对象世界坐标减去相机位置,让相机附近的坐标回到接近零的范围。

这样,GPU 参与顶点变换与光栅化的坐标数值保持较小,能显著改善局部精度。世界逻辑仍可维护全局坐标体系;渲染层则使用局部坐标,二者通过变换矩阵衔接。

10.3 它影响的不只是 Vertex Position

采用相机相对坐标后,依赖世界坐标的系统也要保持一致,例如阴影、植被、粒子、Decal、物理/渲染同步、裁剪与材质中的世界空间效果。否则不同系统可能在不同原点下计算,造成视觉或逻辑错位。

11. 地形要与世界其他元素一起工作

11.1 Decorator Rendering

地形本身通常只是底面。岩石、树木、草、灌木、建筑碎片等 decorator 让场景获得尺度感和辨识度。它们同时带来大数量实例的裁剪、LOD、阴影、密度分布与风动等问题。

一个常见原则是:地形系统输出坡度、高度、材质类型、湿度或遮罩等字段;装饰物系统利用这些字段进行规则分布,而不是由每个系统独立猜测地表语义。

11.2 Road 与 Decal

道路往往由样条线编辑:样条既定义道路路径,也可驱动局部地形抬升、压平或雕刻。Decal 则适合叠加道路边缘、轮胎痕迹、湿地、污渍等局部表面信息。

课程展示了把道路和 Decal 结果写入/叠加到虚拟纹理空间的思路。这样可以避免给每条道路都增加大量独立几何或材质层,同时让道路与基础地形使用一致的流式与 LOD 机制。

11.3 程序化地形创建

程序化生成可以从噪声、规则、侵蚀近似或设计约束出发生成高度、材质分布和装饰物候选点。它的价值不只在“自动造山”,还在于为广阔区域建立可控的初始数据,并把重复性工作交给规则系统。

不过程序化结果仍需要与手工编辑、任务布局、道路、玩法空间和美术方向协作。规模化生成并不替代关卡设计。

12. 本讲的系统性结论

12.1 三个层次必须对齐

层次 关键问题 课程中的代表技术
几何层 哪些区域需要多少三角形,如何无缝连接 LOD、四叉树、TIN、Tessellation、Mesh Shader
表面层 大地表如何呈现多种材料又不压垮像素着色 Splatting、Texture Array、Parallax、虚拟纹理
世界层 如何让大坐标、流式、道路、植被和编辑工具一致工作 Camera-Relative Rendering、DirectStorage/DMA、Decorator、Decal、程序化生成

12.2 最重要的工程取舍

  • 高度场高效,但不能原生表达任意拓扑。
  • 更细网格能提升近景质量,却增加 LOD 连接和吞吐压力。
  • 多材质混合更丰富,却放大纹理采样与显存成本。
  • 虚拟纹理解决“规模”,但要求可靠的缓存、反馈与流式系统。
  • 超大世界可以保留全局逻辑坐标,但渲染应尽量在相机附近的小坐标范围中进行。

13. 复习用速记

13.1 一条因果链

大世界覆盖范围大
→ 不能让所有区域使用同等几何密度
→ 需要视点相关 LOD 与无缝边界策略
→ 高细节地表需要多种材料混合
→ 原始材质层过多会造成带宽与显存压力
→ 虚拟纹理按可见性和 LOD 流式管理 tile
→ 大坐标场景还需要相机相对渲染保持数值稳定
→ 道路、植被、Decal 与编辑工具共享同一世界数据与资源管线。

13.2 容易混淆的概念

概念 主要解决什么 不是用来解决什么
LOD 按可见误差分配几何/纹理预算 任意拓扑表达
Tessellation 在 GPU 上细分控制网格 自动消除所有裂缝与过度细分
Parallax Mapping 增加像素级视差感 改变真实轮廓
Displacement Mapping 改变真实顶点位置 免费获得高密度几何
Texture Splatting 混合多个地表材料 自动解决大世界纹理常驻
Virtual Texture 按页流式管理巨大纹理 省去缓存与 IO 调度
Camera-Relative Rendering 缓解渲染坐标精度问题 取代世界逻辑坐标体系

14. 自测题

  1. 为什么普通高度场难以表达洞穴和悬空地形?
  2. 视点相关误差为什么比单纯“按距离切 LOD”更合理?
  3. 什么是 T-Junction?它会在地形渲染中造成什么问题?
  4. 四叉树和 TIN 各自更擅长解决什么问题?
  5. GPU Tessellation 与 Displacement Mapping 分别承担什么职责?
  6. Mesh Shader 相比传统几何管线带来了哪些可组织空间?
  7. Marching Cubes 在体素地形工作流中的输入和输出分别是什么?
  8. 简单 Texture Splatting 为什么容易出现不自然的平滑过渡?
  9. Height-Based Blending 如何改善材质过渡?
  10. 为什么多材质混合会显著提高像素着色和带宽压力?
  11. 虚拟纹理中的 virtual texture、page table、physical texture 分别是什么?
  12. 为什么虚拟纹理需要处理页缺失、缓存替换和 tile 边界?
  13. 相机相对渲染如何缓解浮点精度误差?
  14. 为什么道路、Decal、植被和地形不能完全作为彼此独立的系统?

15. 术语表

术语 含义
Heightfield 用二维位置映射单一高度值的地形表示
LOD Level of Detail,根据可见性/误差选择不同细节级别
T-Junction 一个网格边上的顶点未与相邻网格对应顶点连接的拓扑情况
Stitching 为不同 LOD 网格边界构造连接关系以避免裂缝
QuadTree 将平面区域递归划分为四个子区域的层级结构
TIN Triangulated Irregular Network,不规则三角网
Tessellation 在 GPU 上对控制网格进行细分的图形管线能力
Mesh Shader 可直接在 GPU 上生成/组织小簇顶点与图元的可编程阶段
Voxel 三维体素网格中的离散单元
Marching Cubes 从体数据的等值面提取三角网格的经典算法
Texture Splatting 用权重控制多个地表材质纹理混合的方法
Texture Array 在单一资源中存放多层同规格纹理的结构
Virtual Texture 以页表映射和物理缓存实现的超大逻辑纹理
Page Table 记录虚拟纹理页到物理缓存页映射的表
Camera-Relative Rendering 以相机附近为局部原点进行渲染,降低大坐标精度误差
Decal 贴附或投射到已有表面上的局部材质/细节效果

16. 参考资料