游戏渲染技术全方位解析 - 从一根头发到一片云的技术全景
游戏渲染技术全方位解析 🎮✨
本文基于网易游戏学堂的技术分享,深入拆解游戏渲染的核心原理——从角色皮肤上的次表面散射,到天空中飘过的体积云,看技术美术如何用代码和数学在屏幕上重构一个真实可感的世界。每个技术点都会讲清楚是什么、为什么、怎么做,辅以数学公式、Shader 伪代码、实际游戏案例和性能数据。
原文: 游戏渲染技术|全方位解析游戏画面的实现逻辑 — 网易游戏学堂
一、什么是游戏渲染?
1.1 定义
游戏渲染(Game Rendering),简单来说就是让你能在显示器上看到游戏画面的技术。更精确地说,它是一系列计算机图形学算法的集合,负责将虚拟的 3D 场景(模型、材质、灯光、动画)转化为显示器上的 2D 像素阵列。
这个过程的本质可以概括为**”光的模拟”**——计算光子从光源出发,经过场景中各种物体的反射、折射、散射后,最终到达虚拟相机传感器的过程。
1.2 20 年的画面进化
| 年份 | 游戏 | 渲染特征 | 技术里程碑 |
|---|---|---|---|
| 1997 | Quake II | 逐像素光照、软件光栅化 | 第一个商业硬件加速 3D 游戏 |
| 2004 | Half-Life 2 | HDR 光照、法线贴图 | Source 引擎的光照系统 |
| 2007 | Crysis | 实时阴影、SSAO、体积光 | “显卡危机”——PC 图形的标杆 |
| 2013 | The Last of Us | 延迟渲染、后处理管线 | 主机平台的 PBR 先驱 |
| 2015 | The Witcher 3 | PBR 材质、开放世界流送 | 大规模场景的 PBR 实践 |
| 2017 | Horizon Zero Dawn | 体积云、大气散射、植被系统 | Decima 引擎的自然环境渲染 |
| 2018 | Red Dead Redemption 2 | 物理天空、全局光照、ECS | 极致的细节和交互 |
| 2020 | Cyberpunk 2077 | RTX 光追、DLSS、虚拟几何 | 光线追踪实时化的先驱 |
| 2022 | Horizon Forbidden West | 体积云升级、水面交互 | 大气渲染的新高度 |
| 2023 | Alan Wake 2 | 全路径追踪、Meshlet | 实时光追的全面突破 |
从 2000 年到 2025 年,游戏画面发生了翻天覆地的变化,但底层做的事情始终如一:通过计算机图形学算法,将 3D 场景转化为 2D 图像。变化的是算法的复杂度和硬件的性能——从简单的 Phong 光照模型,到基于物理的渲染(PBR),再到实时光线追踪。
1.3 渲染管线概览
理解游戏渲染,首先要理解渲染管线(Rendering Pipeline)——从 3D 数据到屏幕像素的完整流程:
1 | |
关键阶段详解:
Application Stage(应用层):CPU 端执行碰撞检测、物理模拟、动画更新、可见性判断。这是唯一完全由开发者控制的阶段。
Geometry Processing(几何处理):顶点着色器(Vertex Shader)执行模型-视图-投影变换(MVP)、法线变换、骨骼蒙皮。可选的曲面细分(Tessellation)和几何着色器(Geometry Shader)在此阶段运行。
Rasterization(光栅化):将三角形转换为像素片段(fragments)。这一步由 GPU 硬件固定管线完成,速度极快。
Fragment Processing(片元处理):像素/片元着色器执行材质计算——这就是 PBR、NPR、SSS 等技术”发生”的地方。每个像素都要执行一次 Shader 程序。
现代引擎还广泛使用延迟渲染(Deferred Rendering)和前向+(Forward+)等变体,它们改变了管线的组织方式,但核心流程不变。
1.4 两种主流渲染架构
| 特性 | 前向渲染(Forward) | 延迟渲染(Deferred) |
|---|---|---|
| 光照复杂度 | O(物体数 × 光源数) | O(像素数 × 光源数) |
| 多光源 | 困难(需要多 pass) | 友好(G-Buffer 解耦) |
| 透明物体 | 天然支持 | 需要额外前向 pass |
| MSAA | 天然支持 | 不兼容(需 FXAA/TAA) |
| 带宽 | 低 | 高(G-Buffer 读写) |
| 代表引擎 | Unity 默认、移动端 | UE4/UE5 默认 |
| 移动端友好度 | ✅ 高 | ❌ 低(带宽开销大) |
Forward+(分块前向渲染)结合了两者的优势:先用深度预pass将屏幕分块,计算每块的光源列表,然后在前向 pass 中只处理相关光源。这是目前主机和 PC 上的主流方案之一。
二、渲染画面的三大核心模块
游戏渲染可以归纳为三个互相交织的核心模块:
| 模块 | 关注点 | 目标 | 技术难度 |
|---|---|---|---|
| 角色(Character) | 材质与交互:头发、皮肤、眼睛、服饰 | 让角色看起来真实或有风格 | ⭐⭐⭐⭐⭐ |
| 场景(Scene) | LOD 与流送:植被、云、水、地形 | 构建可信的游戏世界 | ⭐⭐⭐⭐ |
| 氛围(Atmosphere) | 参数与控制:天气、光影(TOD 时间变化) | 营造沉浸感 | ⭐⭐⭐ |
为什么是这三个模块?
这不是随意的分类,而是反映了游戏画面构成的物理本质:
- 角色是玩家注意力的焦点——人脸识别的本能让玩家对角色的每一处细节都极度敏感。一个微小的皮肤渲染错误(比如看起来像塑料)会立刻破坏沉浸感。
- 场景是玩家活动的空间——它需要足够大(开放世界)、足够丰富(植被、建筑)、足够真实(光影正确),同时又不能超出硬件预算。
- 氛围是情绪的载体——同一个场景,晴天和雨天给玩家的感受完全不同。大气散射、体积云、天气系统是连接角色和场景的”胶水”。
三者的交集:交互
关键洞察:三者并非割裂,而是存在大量交集——这些交集恰恰是技术上最难、也是提升沉浸感最关键的部分:
1 | |
典型的交互渲染效果:
| 交互类型 | 角色侧 | 场景侧 | 氛围侧 | 技术方案 |
|---|---|---|---|---|
| 角色踩水 | 溅水动画 | 水面波纹 | 泥地反射 | 物理模拟 + Render to Texture |
| 风吹头发 | 发丝摆动 | 草地弯曲 | 风向参数 | 风场 + Verlet 积分 |
| 雨天行走 | 湿身效果 | 地面水洼 | 雨滴粒子 | SSS 变体 + 粒子系统 |
| 场景破坏 | 碎片物理 | 几何变形 | 灰尘特效 | Destructible Mesh + GPU 粒子 |
| 雪地行走 | 脚印标记 | 雪地变形 | 积雪厚度 | Splat Map + Tessellation |
理解了这三个模块及其交互,就掌握了游戏渲染的全局视图。接下来我们逐个深入。
三、角色渲染技术详解
角色是游戏画面的核心。一个角色的渲染质量,直接决定了玩家对游戏画面水平的整体评判。
3.1 角色制作流程
从原画设计到游戏画面,角色需经历一个完整的工业化管线:
1 | |
角色材质的两大分类:
- 通用材质库:解决一般物体表面的光照问题。金属、木材、布料、皮革等通过 PBR 参数化描述,一套材质系统覆盖大部分需求。
- 特殊材质:眼球、皮肤、头发、丝袜等需要特殊的 Shader 处理——它们的光照行为无法被标准 PBR 模型准确描述。
通用材质用一套标准化的 PBR 流程就能搞定,但特殊材质才是区分”一般画面”和”3A 画面”的关键。下面我们逐个拆解。
3.2 PBR vs NPR:两大渲染范式
这是游戏渲染中最核心的概念分野。理解它们的差异,是理解后续所有技术的基础。
3.2.1 PBR(基于物理的渲染)
核心思想:用物理公式描述光与材质的交互。给定材质参数(粗糙度、金属度等)和光照条件,渲染结果是确定的、可预测的。
为什么需要 PBR? 在 PBR 时代之前,美术需要手动调整每个材质的每一项参数来”凑出”看起来对的效果。一个问题:在日光下看起来正确的材质,在室内灯光下可能完全不对。PBR 通过物理模型保证了材质在任何光照条件下都正确。
| 特性 | PBR | NPR |
|---|---|---|
| 驱动方式 | 公式驱动(Formula Driven) | 结果驱动(Result Driven) |
| 追求目标 | 物理正确性 | 艺术风格表达 |
| 代表类型 | 写实类游戏 | 二次元 / 风格化游戏 |
| 美术工作流 | 标准化,工具成熟 | 需自定义,成本较高 |
| 光照一致性 | ✅ 任意光照下正确 | ❌ 通常依赖烘焙,动态光需特殊处理 |
| 材质参数 | Roughness, Metallic, AO 等 | 色阶贴图、SDF 轮廓、法线阈值等 |
| 代表游戏 | The Last of Us, Cyberpunk | 原神, 崩坏:星穹铁道, Zelda BotW |
| 工具链 | Substance 生态完善 | 自研 Shader + 美术管线 |
3.2.2 NPR(非真实感渲染)
核心思想:最终效果由美术直接控制,Shader 的角色是”把美术的意图忠实呈现”,而不是”用公式算出物理正确的结果”。
NPR 不是”不追求真实”,而是追求另一种真实——动画、漫画、油画等非写实风格的视觉语言。原神的渲染效果在物理上完全错误(阴影是硬编码的色阶、高光位置不符合物理),但在玩家的感知中,它”看起来就是对的”——因为玩家期待的是二次元风格,而不是物理真实。
3.3 渲染方程:一切 PBR 的基础
所有基于物理的渲染都建立在一个方程之上——渲染方程(Rendering Equation),由 James Kajiya 于 1986 年提出:
$$L_o(\omega_o) = L_e(\omega_o) + \int_{\Omega} f_r(\omega_i, \omega_o) \cdot L_i(\omega_i) \cdot (\mathbf{n} \cdot \omega_i) , d\omega_i$$
这个方程看起来吓人,但拆解后每个部分都有清晰的物理含义:
| 符号 | 名称 | 物理含义 | 直觉理解 |
|---|---|---|---|
| $L_o(\omega_o)$ | 出射辐射度 | 沿观察方向 $\omega_o$ 离开表面的光量 | “你看到了什么” |
| $L_e(\omega_o)$ | 自发光 | 表面自身发出的光 | “它自己是灯泡吗?” |
| $\int_{\Omega}$ | 半球积分 | 对上半球所有方向求和 | “从四面八方收集光线” |
| $f_r(\omega_i, \omega_o)$ | BRDF | 双向反射分布函数 | “这个表面有多能反光?” |
| $L_i(\omega_i)$ | 入射辐射度 | 从方向 $\omega_i$ 来的光量 | “那里有多少光?” |
| $(\mathbf{n} \cdot \omega_i)$ | Lambert 余弦 | 表面法线与入射方向的点积 | “光有多正着照过来?” |
| $d\omega_i$ | 立体角微元 | 方向上的微小变化 | “收集每个方向的一小份” |
直觉翻译:
“你看到的颜色 = 表面自己发的光 + 从四面八方来的光,经过表面反射后的总和。每束入射光的贡献取决于三个因素:光有多强($L_i$)、表面在该方向的反射能力(BRDF)、光线照射的角度(Lambert 余弦项)。”
为什么这个方程重要?
渲染方程是能量守恒的数学表达——表面反射出去的光能永远不会超过接收到的光能。这是 PBR 的基石:只要你的 BRDF 满足能量守恒,材质在任何光照条件下都会表现正确。
为什么渲染方程无法精确求解?
积分域 $\Omega$ 是连续的半球空间——理论上需要无限多次采样才能得到精确解。这就是为什么游戏渲染永远在做近似:
- 实时渲染用环境贴图(Cubemap)或球谐函数(SH)近似 $L_i$
- 离线渲染用蒙特卡洛方法(Monte Carlo)采样估计积分
- 光线追踪用光线采样直接求解积分
3.4 BRDF:表面的”身份证”
BRDF(Bidirectional Reflectance Distribution Function,双向反射分布函数)是渲染方程的核心——它描述了材质的光学特性。不同的材质就是不同的 BRDF。
3.4.1 BRDF 的物理约束
一个物理合理的 BRDF 必须满足:
- 非负性:$f_r(\omega_i, \omega_o) \geq 0$(反射光不能为负)
- 互易律(Helmholtz Reciprocity):$f_r(\omega_i, \omega_o) = f_r(\omega_o, \omega_i)$(交换入射和出射方向,结果不变)
- 能量守恒:$\int_{\Omega} f_r(\omega_i, \omega_o) (\mathbf{n} \cdot \omega_o) d\omega_o \leq 1$(反射出去的总能量不超过入射能量)
3.4.2 从 MERL 数据库到参数化 BRDF
在 PBR 流行之前,研究者用专业设备(测角光度计)测量真实材质的反射特性,建立了 MERL BRDF 数据库(Matusik et al., 2003),包含 100 种真实材质的 BRDF 数据。
MERL 数据库的问题:
| 问题 | 详情 |
|---|---|
| 数据量巨大 | 每个材质 33MB+,100 个材质就是 3.3GB |
| 查询性能低 | 需要三线性插值,GPU 友好度差 |
| 表达能力受限 | 无法表达各向异性(如拉丝金属)、次表面散射等复杂现象 |
| 外推能力差 | 无法从采样数据生成数据库中没有的材质 |
| 参数不直观 | 没有美术能理解的参数化方式 |
这意味着:数据驱动这条路走不通。我们需要参数化的数学模型来近似真实材质。
3.4.3 Disney Principled BRDF(2012)——革命性的简化
Brent Burley 在 SIGGRAPH 2012 发表的 Disney Principled BRDF 带来了革命性的改变。它不是一个新的物理模型,而是一套美术友好的参数化方案,用少数直观参数控制复杂的材质外观。
设计原则:
- 参数直观:用”粗糙度”而非晦涩的”微表面斜率分布参数”
- 参数尽可能少:控制在 10 个左右的关键参数
- 值范围 0-1:标准化,便于理解和调整(美术最喜欢滑块!)
- 允许参数超出范围:在有意义时突破 [0,1] 限制以表达特殊效果
- 组合健壮:任意参数组合不产生明显错误
核心参数详解:
| 参数 | 英文名 | 范围 | 效果说明 | 物理对应 |
|---|---|---|---|---|
| 基础色 | Base Color | [0,1]³ | 材质本身的颜色(非金属)或反射率(金属) | 反射率 albedo |
| 粗糙度 | Roughness | [0,1] | 0 = 镜面光滑,1 = 完全粗糙 | 微表面斜率的方差 |
| 金属度 | Metallic | [0,1] | 0 = 非金属(有漫反射),1 = 金属(无漫反射) | 导体/介质区分 |
| 高光强度 | Specular | [0,1] | 非金属的镜面反射强度 | 菲涅尔 F0 值 |
| 各向异性 | Anisotropic | [0,1] | 反射高光的拉伸程度(如拉丝金属) | 切线方向上的粗糙度差异 |
| 次表面 | Subsurface | [0,1] | 光线在表面下的散射程度 | 次表面散射近似 |
| 光泽 | Sheen | [0,1] | 掠射角的布料光泽 | 织物纤维的散射 |
| 光泽色 | Sheen Tint | [0,1] | 光泽的色调偏移 | — |
| 清漆 | Clearcoat | [0,1] | 表面额外的透明涂层 | 汽车漆面的两层结构 |
| 清漆粗糙度 | Clearcoat Roughness | [0,1] | 透明涂层的粗糙度 | — |
最核心的参数是粗糙度(Roughness)。它和高光的光泽度(Glossiness)是互补关系:Glossiness = 1 - Roughness。不同的引擎用不同的约定——UE 用 Roughness,Unity 的 HDRP 默认也用 Roughness,但一些旧管线用 Smoothness(= 1 - Roughness)。
一个关键的实现细节:在 Metallic/Roughness 工作流中,如果 Base Color 贴图在金属-非金属边界处没有完美对齐,就会产生黑色或白色的边缘伪影。解决方案包括:
- 使用更精确的 UV 和更细致的手绘
- 后处理 dilate/erode 边缘
- Unity HDRP 和 UE5 都有内置的边缘修复选项
3.5 微表面模型(Microfacet Model)
微表面模型是理解 PBR 镜面反射的关键——它是 Disney BRDF 和游戏中几乎所有 Specular BRDF 的理论基础。
3.5.1 核心思想
在微观尺度上,任何表面都不是完全光滑的。微表面模型假设:
表面由无数个微小的、完美镜面的平面组成,每个微平面有自己的法线方向。表面的”粗糙度”由微平面法线分布的集中程度决定。
1 | |
3.5.2 Cook-Torrance BRDF
游戏中最常用的 Specular BRDF 是 Cook-Torrance 模型:
$$f_{specular}(\omega_i, \omega_o) = \frac{D(\mathbf{h}) \cdot F(\omega_o, \mathbf{h}) \cdot G(\omega_i, \omega_o, \mathbf{h})}{4 \cdot (\mathbf{n} \cdot \omega_i) \cdot (\mathbf{n} \cdot \omega_o)}$$
其中 $\mathbf{h} = \frac{\omega_i + \omega_o}{|\omega_i + \omega_o|}$ 是半程向量(Half Vector)。
三个组成部分各有分工:
| 函数 | 名称 | 作用 | 物理含义 |
|---|---|---|---|
| $D(\mathbf{h})$ | 法线分布函数(NDF) | 决定高光的形状和大小 | 微平面的法线朝 $\mathbf{h}$ 方向的概率密度 |
| $F(\omega_o, \mathbf{h})$ | 菲涅尔项(Fresnel) | 决定不同角度的反射率 | 从正面看vs从侧面看的反射强度差异 |
| $G(\omega_i, \omega_o, \mathbf{h})$ | 几何遮蔽项(Geometry) | 补偿自遮挡 | 微平面之间的相互遮挡 |
3.5.3 法线分布函数:为什么选 GGX?
GGX(Trowbridge-Reitz) 是目前最主流的 NDF,由 Walter et al. 2007 提出:
$$D_{GGX}(\mathbf{h}) = \frac{\alpha^2}{\pi \cdot ((\mathbf{n} \cdot \mathbf{h})^2 \cdot (\alpha^2 - 1) + 1)^2}$$
其中 $\alpha = roughness^2$。
GGX vs Beckmann 对比:
| 特性 | Beckmann | GGX (Trowbridge-Reitz) |
|---|---|---|
| 高光形状 | 较平滑的衰减 | 明显的”拖尾”(long tail) |
| 高光核心 | 稍宽 | 更窄、更亮 |
| 材质表现 | 适合塑料、油漆 | 适合金属、玻璃 |
| 为什么选 GGX | — | 更长的拖尾更符合真实金属的反射特性 |
| 代表引擎 | 早期 OpenGL 固定管线 | UE4/5、Unity HDRP、Filament |
拖尾(tail) 是关键区别。真实金属的高光不是完美的圆——它有一条长长的”尾巴”,在远离高光中心的地方仍然有可感知的反射。GGX 的长尾特性恰好匹配了这一现象,这就是为什么所有现代引擎都选择了 GGX。
Shader 伪代码:
1 | |
3.5.4 菲涅尔项:Schlick 近似
菲涅尔效应描述了一个日常现象:从正面看水面是透明的,从侧面看水面是反射的。所有材质都有这个特性。
完整的菲涅尔公式(Fresnel Equation)非常复杂,Schlick (1994) 提出了一个优雅的近似:
$$F_{Schlick}(\cos\theta) = F_0 + (1 - F_0) \cdot (1 - \cos\theta)^5$$
其中 $F_0$ 是垂直入射时的反射率(法线方向的菲涅尔值)。
$F_0$ 的典型值:
| 材质 | $F_0$ (sRGB) | $F_0$ (线性) | 说明 |
|---|---|---|---|
| 水 | 0.02 | (0.02, 0.02, 0.02) | — |
| 塑料 | 0.04 | (0.04, 0.04, 0.04) | 大多数非金属 |
| 玻璃 | 0.04-0.08 | — | — |
| 金 | — | (1.00, 0.71, 0.29) | 有色菲涅尔! |
| 铝 | — | (0.91, 0.92, 0.92) | — |
| 铜 | — | (0.95, 0.64, 0.54) | 有色菲涅尔! |
Shader 伪代码:
1 | |
3.5.5 几何遮蔽项
微平面之间会相互遮挡——这在高粗糙度和掠射角时尤为明显。
Smith-GGX 模型将遮蔽分为两个独立部分:
$$G(\omega_i, \omega_o) = G_1(\omega_i) \cdot G_1(\omega_o)$$
其中 $G_1$ 是方向无关的遮蔽函数。UE4/5 使用的是 Smith-Joint 近似,它是 Smith-GGX 的简化版:
1 | |
3.5.6 完整的 PBR Shader 片段
把所有部分组合起来,一个完整的直接光照 PBR 计算如下:
1 | |
3.5.7 多层材质混合的演进
很多真实材质是多层结构——车漆(清漆+底漆)、湿润的地面(水层+地面)、皮肤(油脂+表皮+真皮)。
多层混合的三种方案:
| 方案 | 思路 | 优点 | 缺点 |
|---|---|---|---|
| 结果混合 | 分别计算两层 BRDF,混合结果 | 简单 | 物理不正确(能量不守恒) |
| 参数预混合 | 在 BRDF 计算前混合参数 | 部分正确 | 无法表达层间多次反射 |
| 分层模型(Slab) | 每层独立光学计算,层间传播 | 物理正确 | 计算量大 |
UE5 的 Strata 系统是第三种方案的代表——它用”slab”概念表达每层的光学结构(折射率、吸收系数、散射系数),层与层之间通过物理公式传播光线,实现了更准确的线性混合。
3.6 NPR(非真实感渲染)风格化
NPR 是游戏渲染的另一半天空——原神、塞尔达、纪念碑谷等风格化游戏都使用 NPR。
3.6.1 核心原则:所见即所得
NPR 的核心哲学是:美术画什么,玩家就看到什么。Shader 的角色是忠实地呈现美术的意图,而不是用公式计算物理正确的结果。
具体实现手段:
贴图即结果:美术画的贴图直接对应最终效果——亮度、阴影、高光都在贴图中预先定义好。
光照烘焙(Baked Lighting in Texture):光照信息预烘焙到贴图中。原神的角色阴影就是一个经典的阶梯函数——通过色阶贴图(Ramp Texture)控制阴影的过渡:
1 | |
- 边缘光(Rim Light):利用菲涅尔系数实现角色与背景的视觉分离:
1 | |
- 屏幕空间轮廓描边:在屏幕空间做卷积得到更精细的边缘检测:
1 | |
3.6.2 描边的多种实现方式
描边是 NPR 中最标志性的视觉效果。不同游戏根据性能和风格需求选择了不同的方案:
| 方案 | 原理 | 优点 | 缺点 | 代表游戏 |
|---|---|---|---|---|
| 法线外扩 | 两遍渲染,第二遍沿法线放大 | 线宽一致 | 需要额外 pass | 崩坏3、战双帕弥什 |
| 后处理边缘检测 | 深度/法线 buffer 做 Sobel | 简单 | 线宽不均 | Guilty Gear Xrd |
| SDF 描边 | 利用 SDF 距离场 | 精确控制 | 需要额外贴图 | 部分手游 |
| 几何着色器 | 沿法线生成额外三角形 | GPU 高效 | 几何着色器慢 | — |
法线外扩描边的 Shader 实现:
1 | |
3.6.3 NPR 的特殊挑战
NPR 面临一些 PBR 不存在的独特问题:
面部阴影控制:由于卡通渲染的阴影是硬边缘的,角色的脸部稍微转动就可能导致阴影突变。解决方案是用一张 SDF 面部阴影贴图 精确控制面部明暗分界线的形状。
多光源处理:PBR 天然支持多光源叠加,但 NPR 的色阶阴影一旦叠加就会失去风格化特征。通常只取主导光源做色阶,其余光源做简单叠加。
LOD 一致性:角色远距离时,描边线宽需要随距离缩放,否则会出现”远景描边比角色还粗”的问题。
3.7 皮肤渲染(Skin Rendering)
皮肤是角色渲染中最复杂的特殊材质之一。理解皮肤渲染需要从皮肤的物理结构出发。
3.7.1 为什么皮肤不能直接用 PBR?
皮肤的物理结构是多层的半透明介质:
1 | |
关键现象:光线进入皮肤后,在真皮层中经历多次散射,路径长度可达数毫米。短波光(蓝色)被血红蛋白大量吸收,而长波光(红色)更容易穿透——这就是为什么手指对着光看会呈现红色透光效果。
3.7.2 次表面散射(Subsurface Scattering, SSS)
SSS 是让皮肤看起来”活”的关键。没有 SSS 的皮肤看起来像塑料,因为光线在边界处被硬切断——而真实的皮肤中,光线会在皮下扩散,产生柔和的明暗过渡。
核心现象:
- 正面通透感:亮部到暗部的柔和过渡——阴影边界不是锐利的,而是模糊的
- 背面透射:光从背面穿透薄皮肤(耳朵、手指之间的缝隙发红光)
- 细节高光:油脂层产生的细小高光——比一般的 Specular 更锐利
3.7.3 SSS 的实现方案
| 方案 | 原理 | 性能 | 适用场景 | 代表游戏/引擎 |
|---|---|---|---|---|
| 纹理空间模糊(TSSS) | 在 UV 空间做高斯模糊 | 中 | 主机/PC | UE4 早期方案 |
| 屏幕空间模糊(SSSSS) | 在屏幕空间沿法线方向模糊 | 中-高 | 主机/PC | GDC 2015 方案 |
| 预积分皮肤 Shader | 用预计算 LUT 近似 SSS | 低 | 移动端/全平台 | UE4 Mobile |
| 可分离 SSS | 将 2D 模糊分离为两次 1D | 中-高 | 主机/PC | UE4/UE5 默认 |
| 路径追踪 SSS | 随机游走模拟 | 极高 | 离线/RTX | UE5 Lumen+RT |
预积分皮肤 Shader 是移动端最实用的方案。核心思想:预计算一个 LUT(查找表),输入曲率和 NdotL,输出 SSS 近似结果。
1 | |
为什么预积分有效? SSS 的核心效果是模糊阴影边界和增加暗部亮度。通过对不同曲率的表面预计算这个模糊效果,可以用一个简单的纹理采样代替运行时的卷积操作。
曲率(Curvature) 的计算:
1 | |
3.7.4 背面透射
耳朵、手指等薄皮肤部位的背面透射效果:
1 | |
3.8 头发渲染(Hair Rendering)
头发渲染的特殊性在于:头发是圆柱形的纤维,不是平面。这导致光在发丝上的行为与普通表面完全不同。
3.8.1 头发的光学特性
一根头发纤维的光路行为有三种:
1 | |
- R(Reflection):直接反射,产生主要高光
- TT(Transmission-Transmission):同侧透射,产生头发的半透明感
- TRT(Transmission-Reflection-Transmission):穿透散射,产生次级高光和颜色偏移
3.8.2 Kajiya-Kay 模型(1989)
Kajiya-Kay 是最早的头发光照模型之一,至今仍是手游的主流选择——因为它足够简单。
核心思想:用切线方向(而非法线)计算高光。因为头发是圆柱形的,法线在截面上处处不同,但切线方向是一致的。
1 | |
优点:计算简单,一个 dot + pow 就搞定。移动端友好。
缺点:物理不准确——没有区分 R/TT/TRT 三条光路,高光形状是各向同性的(真实头发的高光应该沿发丝方向拉伸)。
3.8.3 Marschner 模型(2003)
Marschner 模型完整地解决了 R、TT、TRT 三条光路,是 3A 游戏头发渲染的标准方案。
核心贡献:
- 建立了头发纤维的椭圆截面模型
- 推导了每条光路的精确 BRDF
- 发现了高光会随光线入射角偏移(不是在法线方向上,而是在切线方向上偏移)
实现方案:完整的 Marschner 计算量很大(需要大量三角函数和指数运算),所以实际游戏中都用预计算 LUT:
1 | |
实际使用中,Frostbite(EA)和 UE5 都采用了 Marschner 的简化变体,通常只保留 R 和 TT 项(TRT 用近似代替),并将 LUT 压缩到更小的纹理中。
3.8.4 头发建模方案
| 方案 | 面数 | 效果 | 性能开销 | 适用场景 |
|---|---|---|---|---|
| Card(卡片) | 低(几十个面片) | 中等 | 低 | 手游、远处 LOD |
| Strand(发丝级) | 高(每根发丝一条曲线) | 最好 | 高(需特殊管线) | 3A 近景 |
Strand Hair 在 UE5 中通过 Groom 系统实现,支持物理模拟和自阴影。但发丝级渲染的开销非常大——一个角色可能有 10000+ 根发丝,每根都要独立计算光照。
3.9 眼球渲染(Eye Rendering)
眼球是角色中最复杂的小型渲染对象。关键在于精确的结构拆解——眼球不是一个球体,而是一个多层光学系统。
3.9.1 眼球的光学结构
1 | |
3.9.2 眼球渲染的技术要点
1. 角膜折射
角膜是一个凸面透镜,光线在进入眼球时会发生折射。使用 Snell 定律:
$$n_1 \sin\theta_1 = n_2 \sin\theta_2$$
其中 $n_1 = 1.0$(空气),$n_2 \approx 1.376$(角膜)。
1 | |
2. 虹膜散射
虹膜的纹理不是简单的平面贴图——它是一个半透明的散射介质。光线进入虹膜后会在内部散射,导致虹膜颜色看起来有深度感。
3. 巩膜 SSS
白眼球(巩膜)不是纯白的——它有血管纹理,并且表现出次表面散射效果。通常使用与皮肤相同的 SSS Shader,但参数不同。
4. 泪膜高光
泪膜是角膜表面的一层极薄的液体,产生非常锐利的高光反射点。这个高光是眼球看起来”有神”的关键。
3.9.3 最新趋势
- 肌肉跟随:眼球的运动不是简单的旋转——周围有 6 条肌肉控制,限制了眼球的运动范围和速度
- Look At 功能:角色的视线追踪目标,需要精确的 IK 计算
- 微表情:瞳孔大小变化、眨眼频率、视线方向都是角色表现力的关键
- Caustics inside eye:光在眼球内部产生的焦散效果,让虹膜看起来更有层次
角色渲染小结
核心原则:用更低成本达到更好效果。
| 渲染技术 | 性能开销 | 视觉提升 | 推荐平台 |
|---|---|---|---|
| 标准 PBR | 基准 | 基准 | 全平台 |
| SSS 皮肤 | 中-高 | 显著 | PC/主机 |
| 预积分 SSS | 低 | 中 | 全平台 |
| Kajiya-Kay 头发 | 低 | 中 | 移动端优先 |
| Marschner 头发 | 中-高 | 显著 | PC/主机 |
| 精细眼球 | 低 | 中(近距离才有效果) | 全平台 |
| NPR 色阶 | 低 | 取决于风格 | 全平台 |
PBR 方案因标准化工作流而成本更低;NPR 方案需自定义工具链,成本较高。**选择的关键不是”哪个更好”,而是”哪个更适合你的游戏风格和目标平台”**。
四、场景渲染技术详解
场景渲染的目标是构建一个可信的游戏世界。与角色渲染不同,场景渲染的核心挑战不是”单个物体的质量”,而是”大规模内容的效率”。
4.1 场景制作的 PCG 流程
现代 3A 游戏的场景规模已经达到了惊人的程度——《荒野大镖客2》的地图约 29 平方英里,纯手工制作是不可能的。程序化内容生成(PCG) 是解决方案。
| 步骤 | 工具/技术 | 输出 | 人工干预程度 |
|---|---|---|---|
| 地形生成 | 高度图雕刻(World Machine/Gaea) | 基础地貌 | 低 |
| 河流切割 | 程序化侵蚀模拟 | 河道、冲积扇 | 低 |
| 悬崖细节 | Houdini 程序化建模 | 岩石细节 | 中 |
| 植被布置 | 生态刷子(Scatter Tool) | 树木、草地 | 中 |
| 建筑放置 | PCG + 手动调整 | 村庄、城市 | 高 |
| 最终整合 | 场景编辑器(UE5/Unity) | 完整场景 | 高 |
UE5 的 PCG 框架是目前的最佳实践——它用图节点(Graph Node)描述生成规则,支持实时预览和迭代,并可以与 Houdini 等外部工具通过 Houdini Engine 插件对接。
4.2 地形渲染(Terrain Rendering)
4.2.1 何时需要地形系统?
| 场景规模 | 推荐方案 | 理由 |
|---|---|---|
| < 200 米 | 普通网格模型 | 地形系统有额外开销,小场景不值得 |
| 200 米 - 1 公里 | 视情况选择 | 评估性能预算和内容需求 |
| > 1 公里 | 地形系统(推荐) | 网格模型数据量太大,必须用 LOD 管理 |
| 1000+ 平方公里 | 大世界地形系统 | 需要 Streaming + GPU Driven + 分页 |
4.2.2 高度图(Heightmap)
地形渲染的基础数据结构是高度图——一个 2D 数组,每个像素存储一个高度值。
1 | |
参数选择:
- 分辨率:通常 1 米/像素到 0.5 米/像素。一个 4km × 4km 的地形,1m 分辨率需要 16M 个采样点
- 精度:8-bit(256 级,适合平缓地形)或 16-bit(65536 级,适合高山)
- 存储:16-bit float(half float)是最佳选择——节省空间且精度足够
从高度图生成网格:
1 | |
4.2.3 LOD(Level of Detail)
地形 LOD 的核心问题:远处的地形需要较少的三角形,近处的需要较多。如何在不产生裂缝(crack)的情况下实现平滑过渡?
Clipmap 方案:
1 | |
四叉树(Quadtree)方案:
将地形分成四叉树结构,每个节点可以独立选择 LOD 等级。UE4/UE5 的地形系统使用的就是这种方案。
1 | |
消除 LOD 裂缝(Crack Fixing):
当相邻的两个 LOD 等级不同时,会在接缝处产生”裂缝”。常见的解决方案:
- 裙边(Skirt):在 LOD 块的边缘向内添加一圈额外三角形,遮挡裂缝
- 过渡区(Transition):在接缝区域做几何 Morph(逐顶点插值)
- T-Junction 消除:在低 LOD 的一侧添加额外顶点匹配高 LOD
4.2.4 GPU Driven 地形
传统地形在 CPU 端生成网格,然后上传到 GPU。GPU Driven 方案直接在 GPU 上生成地形网格,CPU 只发送高度图和 LOD 参数。
1 | |
性能对比:
| 方案 | CPU 开销 | GPU 开销 | 带宽 | 适用场景 |
|---|---|---|---|---|
| CPU 生成 | 高(逐帧更新) | 低 | 高(每帧上传 VB) | 小地形 |
| GPU Driven | 极低 | 低-中 | 低(只传参数) | 大世界 |
| Mesh Shader | 极低 | 低(硬件加速) | 最低 | RTX 30+ / RDNA2+ |
4.2.5 地形材质混合
真实的地形不是单一材质——山坡是岩石,平地是草地,低洼处是泥土。需要混合多种材质。
权重图(Splat Map / Weight Map):
每个像素存储各材质层的权重(总和 = 1)。例如 4 层材质需要 RGBA 四个通道。
1 | |
优化策略:
- 只保留权重最高的两层:大多数像素只有 1-2 层材质占主导,省略次要层可以减少采样次数
- Virtual Texture(VT):将混合结果预计算到虚拟纹理中,运行时只需一次采样。UE5 的 Virtual Texture 系统就是这个思路
4.3 植被系统(Vegetation System)
植被渲染的核心挑战:在有限性能预算内渲染足够密度的植被。《荒野大镖客2》中有超过 300 种植物,每种可能有上千个实例。
4.3.1 渲染方案选择
| 方案 | 描述 | 三角形数 | 性能 | 代表游戏 |
|---|---|---|---|---|
| Billboard | 永远面向相机的面片 | 2 | 极低 | 远景植被 |
| Cross-Plane | 两个交叉面片 | 4 | 低 | 手游植被 |
| Impostor | 多角度烘焙到面片 | 8-24 | 中 | 中远景植被 |
| 简化 3D 模型 | 低面树模型 | 100-500 | 中-高 | 近景植被 |
| 完整 3D 模型 | 高精度模型 | 1000+ | 高 | 极近距离 |
LOD 策略通常是组合使用:远处用 Billboard,中距离用 Impostor,近处用简化/完整模型。
4.3.2 创作方式
- 密度图刷(Density Map Brush):用刷子绘制密度值,运行时根据阈值生成植被实例。适合大范围的草地、灌木。
- 精确撒点(Manual Placement):手动指定每个植被的位置。适合需要精确控制的区域,如村庄周围的花园。
- 生态规则(Ecological Rules):PCG 根据高度、坡度、湿度等参数自动决定植被种类和密度。UE5 PCG 框架的强项。
4.3.3 植被交互:风场与物理
植被不是静止的——风会吹动草和树,角色经过会压弯草丛。这些交互是提升沉浸感的关键。
风场模型(Wind Field):
1 | |
角色交互:角色附近绑定一个”风力源”,当角色经过植被时,风力源对附近的植被施加力——本质上就是牛顿力学 F = ma。植被的弯曲程度与距离成反比。
4.4 水体渲染(Water Rendering)
水是游戏场景中最复杂也最迷人的渲染对象。真实的水体需要同时处理反射、折射、波浪、焦散等多个光学现象。
4.4.1 波浪模拟
水体表面的波浪可以用不同的数学模型描述:
| 方案 | 原理 | 复杂度 | 适用场景 |
|---|---|---|---|
| 正弦波叠加 | 多个不同频率的正弦波叠加 | 低 | 简单水面 |
| Gerstner Wave | 圆形运动的水面质点 | 中 | 写实海面 |
| FFT 海洋 | 频域统计模型 + FFT | 高 | 3A 海洋 |
| 物理模拟(Shallow Water) | Navier-Stokes 简化 | 极高 | 河流、水池交互 |
Gerstner Wave 是最常见的方案,它比简单的正弦波更真实——因为 Gerstner Wave 的水面质点做的是圆形运动,产生的波峰更尖、波谷更宽,这与真实海浪的形状一致:
1 | |
FFT 海洋是最高端的方案,基于 Tessendorf (2001) 的统计模型。核心思想:海洋表面可以看作大量不同频率、不同方向的波浪的叠加——这在频域中可以用 FFT 高效计算。代表游戏:《盗贼之海》、《死亡搁浅》。
4.4.2 水体光照成分
水体渲染需要同时处理多个光学现象:
1. 反射(Reflection)
水面像一面镜子,反射天空和周围的场景。
| 方案 | 原理 | 质量 | 性能 |
|---|---|---|---|
| Planar Reflection | 从水面下方翻转会渲染整个场景 | 高 | 高(额外一帧渲染) |
| SSR(Screen Space Reflection) | 在屏幕空间追踪反射光线 | 中 | 中 |
| Cubemap Reflection | 用预烘焙的环境贴图 | 低 | 低 |
| Ray Traced Reflection | 光线追踪 | 最高 | 极高(需 RTX) |
2. 折射(Refraction)
透过水面看到的水下场景。使用 Snell 定律偏移水下图像的 UV:
1 | |
3. 焦散(Caustics)
水面波浪聚焦光线形成的光斑——就像游泳池底部的波纹光网。
1 | |
4. 次表面散射(SSS)
水的通透感——阳光照射下的水面边缘会发出蓝绿色的光。这与皮肤 SSS 的原理相同。
5. 深浅颜色渐变
浅水区域(岸边)呈现透明的浅蓝绿色,深水区域呈现深蓝色。使用指数衰减模拟水的吸收:
1 | |
4.4.3 水体网格 LOD(CDLOD)
水体使用 CDLOD(Continuous Distance LOD) 实现平滑过渡:
1 | |
4.5 天气系统:天空、大气、云、雾
这一组技术有一个统一的核心算法:Ray Marching(光线步进)。所有介质(大气、云、雾)的光照问题都可以通过这一算法求解。
4.5.1 Ray Marching 核心算法
Ray Marching 的思想非常直观:沿着光线方向一步步前进,每一步计算该位置的密度和光照贡献,累积起来就是最终效果。
1 | |
4.5.2 物理大气(Atmospheric Scattering)
天空不是蓝色的”背景板”——它是一个巨大的发光球壳。蓝色的天空是大气散射的结果。
经典论文:Preetham et al. (2008)《A Practical Analytic Model for Daylight》
物理模型:两层壳模型
1 | |
两种散射类型:
| 散射类型 | 粒子大小 | 效果 | 公式 |
|---|---|---|---|
| 瑞利散射(Rayleigh) | << 光波长 | 蓝天、日落红霞 | $\sigma_s \propto \frac{1}{\lambda^4}$ |
| 米氏散射(Mie) | ≈ 光波长 | 雾天、光晕 | 前向散射为主 |
为什么天空是蓝色的? 瑞利散射强度与波长的四次方成反比。蓝光(λ≈450nm)的散射强度约是红光(λ≈650nm)的 $(650/450)^4 ≈ 4.3$ 倍——所以白光经过大气后,蓝光被大量散射到各个方向,形成了蓝色的天空。
为什么日落是红色的? 日落时太阳光穿过的大气层更厚,蓝光已经被散射殆尽,只剩下红光和橙光能到达你的眼睛。
预计算 LUT 方案:
完整的物理大气计算每帧开销太大(每像素都要做 Ray Marching),所以业界使用预计算查找表(LUT):
1 | |
多次散射:光在大气中会经历多次散射(散射出去的光又散射回来)。单次散射只能产生简单的蓝天效果,而多次散射才能产生真实的地平线泛白、日落时的橙色渐变。实现方式是迭代 LUT——用前一次的结果作为输入计算下一次。
4.5.3 大气雾(Aerial Perspective)
问题:传统的高度雾(Height Fog)与物理大气渲染是割裂的——天空用的是大气散射,地面用的是简单的指数雾。两者在衔接处会有明显的颜色/密度跳变。
解决方案:使用深度切片(Froxel)将大气计算融入统一的框架。
1 | |
通过在每个 Froxel 中计算散射和透射率,大气雾与天空渲染完全统一——不再有”天空”和”雾”的割裂感。
4.5.4 体积云(Volumetric Cloud)
体积云是场景渲染中最耗性能但也最壮观的效果。
核心方案:3D 密度场 + Ray Marching
1 | |
噪声函数:云的形状由噪声函数定义。
| 噪声类型 | 特点 | 用途 |
|---|---|---|
| Perlin Noise | 平滑的梯度噪声 | 云的大致形状 |
| Worley/Voronoi | 细胞状结构 | 云的细节(蓬松感) |
| 分形叠加(FBM) | 多个八度叠加 | 自然的多尺度细节 |
1 | |
云的层级化方案(根据性能预算选择):
| 类型 | 实现方式 | 性能 | 视觉质量 | 适用平台 |
|---|---|---|---|---|
| 雾(低层云) | 体积雾方案 | 低 | 低 | 全平台 |
| 普通云层 | Billboard/Impostor | 中 | 中 | 全平台 |
| 精灵云 | 精灵层叠 | 中 | 中-高 | 主机 |
| 体积云 | Ray Marching 密度场 | 高 | 高 | PC/主机 |
| 高品质体积云 | 多散射+锥形采样 | 极高 | 最高 | 高端 PC |
性能数据参考(1080p 分辨率):
| 云方案 | Ray March 步数 | GPU 时间 | 代表 |
|---|---|---|---|
| 简单体积云 | 32 步 | ~2ms | Unity 默认 |
| 中等体积云 | 64 步 | ~4ms | UE4 插件 |
| 高品质体积云 | 128 步 + light march | ~8-12ms | 《地平线》 |
| 超高品质 | 256 步 + multi-scatter | ~15-20ms | 《死亡搁浅》 |
4.5.5 天气系统的时间控制(TOD)
TOD(Time of Day) 系统是连接所有天气元素的控制层:
1 | |
UE5 的天气系统通过一个统一的 Sky Atmosphere 组件 + Exponential Height Fog + Volumetric Cloud 三者联动实现 TOD 控制。
场景渲染小结
场景制作的三大挑战:
| 挑战 | 说明 | 核心技术 |
|---|---|---|
| 内容 | 创作工具(笔刷、PCG、AIGC)决定生产效率 | Houdini, UE5 PCG, AI 辅助 |
| 性能 | LOD、剔除、流送、GPU Driven | Nanite, Virtual Texture, Streaming |
| 效果 | 风/水交互、场景破坏、UGC 挖洞等 | 物理模拟, Destructible Mesh |
五、总结与实战指南
5.1 渲染技术选择原则
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 写实类 3A 游戏(PC/主机) | PBR + 物理准确方案 + SSS + Marschner | 硬件预算充足,追求极致效果 |
| 移动端写实游戏 | 简化 PBR + LUT 预计算 + Kajiya-Kay | 性能敏感,需要预计算优化 |
| 二次元/风格化 | NPR + 所见即所得 + 色阶阴影 | 艺术风格驱动,不是物理正确驱动 |
| 混合风格 | 分层材质系统(如 UE5 Strata) | 支持多层材质的物理正确混合 |
| 开放世界 | LOD + Streaming + GPU Driven | 大规模场景管理的核心 |
| 竞技/电竞 | 最低延迟 + 稳定帧率 > 画质 | 画面质量服从竞技需求 |
5.2 不同平台的技术选型对比
| 技术领域 | PC/主机(PS5/XSX) | 移动端(骁龙8 Gen3) | Web/小程序 |
|---|---|---|---|
| 渲染架构 | 延迟渲染 / Forward+ | 前向渲染(TBDR) | 前向渲染 |
| PBR | Cook-Torrance 完整版 | 简化版(无 GGX 长尾) | 基础 PBR |
| 阴影 | CSM + Contact Shadow | CSM + 简化 | 单一 Shadow Map |
| SSS | 屏幕空间/可分离 | 预积分 LUT | 无 / 简化 tint |
| 头发 | Marschner + Strand | Kajiya-Kay + Card | Card / 无特殊处理 |
| 地形 LOD | GPU Driven + Nanite | 简化 Clipmap | 固定 LOD |
| 水体 | Gerstner + FFT | 正弦波叠加 | 法线贴图模拟 |
| 大气 | 物理大气 + 体积云 | 简化天空盒 | 天空盒 |
| 后处理 | TAA + SSR + Bloom | FXAA + 简化 Bloom | 基础后处理 |
| 光追 | RT 反射/阴影/GI | 无 | 无 |
| 帧率目标 | 60fps(4K)/ 30fps(光追) | 30-60fps(1080p) | 30fps(720p) |
5.3 性能优化通用套路
LOD 策略:距离越远,细节越少。不只是几何 LOD,还有 Shader LOD(远处用更简单的材质)和阴影 LOD(远处物体不产生阴影)。
剔除优化:
- 视锥剔除(Frustum Culling):不在视野内的物体不渲染
- 遮挡剔除(Occlusion Culling):被其他物体遮挡的不渲染
- 距离剔除(Distance Culling):超过一定距离的小物体直接不渲染
流送管理(Streaming):只加载玩家周围的资源。Mipmap 的本质就是一种流送——远处用低分辨率贴图。
GPU Driven:让 GPU 承担更多工作。Nanite 的核心思想就是完全在 GPU 端管理 LOD 和剔除。
预计算 LUT:空间换时间。SSS、大气、BRDF 都可以用预计算查找表将运行时计算变为纹理采样。
实例化渲染(Instancing):相同几何体的多个实例,一次 Draw Call 渲染全部。植被系统的核心优化手段。
5.4 核心学习路径
1 | |
写在最后
“渲染的本质是用最低的成本,达到最好的效果。”
游戏渲染是一个效果、性能、成本三者平衡的艺术。没有银弹方案,只有最适合当前项目的选择。
从渲染方程的数学精确性,到 NPR 色阶贴图的艺术自由度;从微表面模型的统计学优雅,到体积云 Ray Marching 的暴力美学——每一个像素背后,都是数学和工程的精密配合。
理解底层原理,不是为了能写出更复杂的公式,而是为了在遇到问题时能找到正确的近似方向。渲染方程的精确解不可能实时算出,但理解它之后,你就知道每一次近似牺牲了什么、保留了什么、在什么条件下近似会失效。
这正是游戏渲染技术的魅力所在——在无限的可能性中,找到有限预算下的最优解。
本文基于网易游戏学堂的技术分享整理扩展,融入了图形学经典论文和实际游戏引擎的实现经验。如有疏漏,欢迎指正。