The Technical Art of The Last of Us Part II
The Technical Art of The Last of Us Part II by Waylon Brinck and Steven Tang || SIGGRAPH 2020 - YouTube
项目背景与技术挑战
团队角色定位
- Naughty Dog 的 技术美术(Technical Artist) 定位为 "半程序员、半艺术家" ——既有计算机科学学位,也掌握构图、色彩理论等美术知识,并熟悉实际资产制作的工具与工作流。
- 本次演讲涵盖两方面:具体 渲染技术 与技术美术团队在生产过程中的 成长与升级 。
从《神秘海域4》到《最后生还者 Part II》的跨越
- 《神秘海域4》 的渲染已达到里程碑级水准(详见 SIGGRAPH 2016 演讲)。
- 《最后生还者 Part II》 面临全新且更困难的渲染挑战:
- 大量场景依赖 环境光照(Ambient Lighting) ——这是极难做好的视觉风格,缺乏强烈直射光来"掩盖"材质缺陷。
- 大量 玻璃、雨水 及其他复杂表面。
- 环境种类远超以往任何项目。
- 细节关注度极高 ,早期角色渲染测试暴露出巨大差距。
- 结论:不仅要升级 技术本身 ,还要升级 技术美术团队的工作方式 。
Naughty Dog Uber Shader 系统
总体概况
- Uber Shader 驱动游戏中 几乎所有表面 ,仅有天空、水体和粒子例外。
- 代码量约 48,000 行 (不含生成代码)。
- 这是项目 最先着手 的工作:清理旧有混乱接口、重构代码,为后续功能打下坚实基础。
核心架构:分层材质系统(Layer-Based Material System)
基本概念
- 材质由 多个层(Layer)逐层叠加 构建,概念类似 Photoshop 图层 。
- 示例:一个地面材质 = 混凝土底层 + 油毡层 + 湿润层 + 污渍层。
- 每个层可以是独立的 单层材质 ,在关卡其他地方单独使用,美术通过 合成(Composite) 将它们组合成一个多层材质。
界面设计
| 面板 | 功能 |
|---|
| Layers Panel(图层面板) | 显示图层堆栈,蓝色边框标识 继承自其他材质(Inherited) 的层 |
| Features Panel(功能面板) | 控制该层启用哪些功能(基础 / 高级) |
| 多标签页(Tabs) | 每个标签页控制该层行为的不同方面(BRDF、混合、UV 等) |
BRDF 参数体系
主要参数
- 包含业界常见参数,同时有 Naughty Dog 独有参数 :
- Height Map(高度图) ——用于层间混合与视差效果
- Fuzz(绒毛/模糊) ——非标准参数,用于布料等特殊表面
- 还包含写入 G-Buffer 的其他数据:光照数据、 运动向量(Motion Vectors) 等。
- 针对 皮肤(Skin) 和 头发(Hair) 等有专门的特殊参数(详见 Ramy 在 SIGGRAPH 2016 的演讲)。
G-Buffer 设计
- 整体概念延续了 G-Buffer 打包(Packing) 与 延迟排列(Deferred Permutations) 的方案。
- 相比《神秘海域4》,G-Buffer 通道做了 大幅调整 。
参数交互设计原则
- 每个参数的界面 尽可能简洁 ,内建少量最常用的操作与调整。
- 特殊参数(如 Wetness / 湿润度 )独立于图层堆栈进行 累积(Accumulate) ,最终统一修改 BRDF 输出值后写入 G-Buffer。
- 高级参数放在 子菜单中隐藏 ,既方便新手 发现功能 ,又让资深美术拥有 更强能力 。
Shader Package(着色器包)
- Shader Package 并非特殊机制,而是一组 预打包的控件集合 ,用于更复杂的功能设定。
- 通常影响 多个 BRDF 参数 ,或由 Gameplay 事件驱动 。
- 典型示例—— 角色脏污包(Character Dirt Package) :
- 同时影响 颜色(Color) 、 法线(Normal) 和 粗糙度(Roughness) 。
- 内置与 Gameplay 事件动态联动的全部代码。
层间混合系统(Layer Blending)
基础混合模式
- 示例:红色实色层叠加在 50% 灰色层之上。
- 美术开启 基于顶点色(Vertex Color) 的混合模式即可简单混合。
丰富的混合方式
| 混合类型 | 说明 |
|---|
| 纹理混合(Texture Blend) | 基于贴图进行混合 |
| 斜面混合(Slope Blend) | 基于世界空间中的 顶点法线 进行混合 |
| 各类调整 | 对最终混合结果或中间步骤结果调节 对比度、柔和度 等 |
Blend Mode Previous(前层混合模式)
- 取 上一层的最终混合结果 ,应用到当前层进行 调制(Modulate) 。
- 非常适合 继承(Inheritance) 场景:美术想让某层受限于前一层的混合结果,但不想重复创建复杂的混合设定。
累积高度图(Accumulated Height Map)
- 可以使用 当前层以下所有层的累积高度图 进行混合判断(后续会详细讨论)。
UV 流系统(UV Streams)
基础功能
- 支持 选择 UV 集(UV Set) 和标准变换。
- UV 流 不与层绑定 ——美术可为每层选择不同 UV 流,或所有层复用同一流。
高级功能
| 功能 | 说明 |
|---|
| 视差遮蔽映射(Parallax Occlusion Mapping / POM) | 基于高度图的深度视差 |
| UV 扭曲(Distortion) | UV 变形效果 |
| UV 动画(Animation) | 各类 UV 滚动/动画效果 |
Flow 技术(重点)
- 由程序员 Carlos 开发的 Flow 技术 :
- UV 持续滚动,但在 两个相位偏移的纹理采样之间交叉淡入淡出(Crossfade between two phase-shifted texture samples) 。
- 这防止了 UV 值不断增大时纹理被 拉伸到无穷 的问题。
- 该技术被 完全集成 到整个 Uber Shader 架构中:
- 每个纹理采样器、每个标签页 都能以这种 多采样相位偏移模式 运行。
- 美术无需特殊设置;技术美术添加新采样器时也自动兼容。
- 附带优化细节(对美术不可见):
- 任何 UV 动画控件会 自动写入正确的运动向量(Motion Vectors) ,确保时间抗锯齿(TAA)等后处理正常工作。
排列组合爆炸与优化策略(Permutation Management)
问题
- 每当美术开启新功能,就会生成一个 新的 Shader 二进制(Shader Binary) 。
- 美术需要承担相应的 CPU 开销和关卡内存成本 。
- G-Buffer Pass 基本上 每个材质对应一个唯一 Shader Binary 。
优化手段
- 编程团队进行了 去重优化(Deduplication) :针对 深度(Depth)和阴影(Shadow) 等 Pass 合并相同的 Shader Binary。
- 尽管优化需要投入大量时间,团队认为这种 材质多样性对最终画面效果至关重要 。
特殊功能示例
Border Blend(边界混合)
- 位于 BRDF 标签页的特殊功能,简化常见操作。
- 典型用例:当一个材质继承叠加到另一个材质之上时,过渡区域 几乎总需要特殊处理。
- 例如:涂漆石膏(Painted Plaster)在过渡区域呈现 更暴露、更脏湿 的外观。
- Border Blend 封装了美术所需的全部过渡功能。
- 该功能最初设计简单,但因使用频率极高,最终接口变得更复杂——美术乐于接受,因为它极大简化了材质创建:
- 可以在两层 过渡区域中采样一张完全不同的纹理 ,这对最终效果至关重要。
智能贴花系统(Smart Decals)
- G-Buffer 被 解包为一个虚拟层(Virtual Layer) ,位于贴花图层堆栈的最底部。
- 美术可以使用 任何混合操作 来对下方表面的 G-Buffer 通道进行混合。
- 优势:
- 贴花在 多种不同表面上高度复用 。
- 贴花能 响应其覆盖表面的属性 。
- 可使用下方表面的 高度图(Height Map) 实现更丰富的混合效果。
阶段总结与设计哲学
- 虽然 Uber Shader 架构在《神秘海域4》中已建立,但团队抓住机会进行了 全面改进与标准化 。
- 核心设计哲学:
- 聚焦于 小型、可复用的模块(Small, Reusable Modules) 。
- 代码库保持 整洁 → 材质 优化良好且易于扩展 。
- 界面设计兼顾 新手友好 与 高级能力 。
- 最终成果:一个对美术 易用 、功能 极其丰富 的着色器系统,为后续所有渲染特性的开发奠定了坚实基础。
团队协作模式的反思与重建
问题的暴露
- 技术美术团队在项目推进过程中,逐渐形成了 不健康的工作习惯 :
- 技术美术变成了程序团队与美术团队之间的 一堵墙(Wall) ,而非桥梁。
- 程序员感觉自己成了 服务部门(Service Department) ,而非美术的 合作伙伴(Partners) 。
- 程序员 失去了创造性协作的参与感 ,觉得自己与游戏脱节,工作 得不到认可 。
改进计划
- 经过深思熟虑,团队制定了 回归正轨的方案 ,核心方向有三点:
| 目标 | 具体含义 |
|---|
| 从墙变为桥梁 | 技术美术应当 促进 程序与美术的直接沟通,而非 阻隔 |
| 健康的协作机制 | 在复杂系统开发上建立 合理的分工与协作流程 |
| 提升代码标准 | 技术美术的代码质量虽不必完全达到程序员水平,但需达到 让程序员信任 的程度 |
- 这既是为了 项目质量 ,也是为了修复 团队关系 。
高度图(Height Map)深度集成
这项技术既是重要的渲染升级,也是团队 实践新协作标准 的试金石。
高度图的历史与新定位
- Naughty Dog 从 《神秘海域1》 起就使用高度图作为 混合遮罩(Blend Mask) 。
- 在《最后生还者 Part II》中,团队看到了高度图在 整个管线中更广泛应用 的潜力,决定进行 深度集成 。
界面与参数设计
设计原则
- 界面尽可能 简洁且规范 。
- 所有缩放单位统一为 厘米(cm) ,最大范围 ±10 cm 。
- 源纹理中灰度值 0.5 = 中性高度(Neutral Height) ,美术对此非常直观熟悉。
主要功能
- 凸起效果(Raised) :让表面层向上突出,如砖墙上的灰泥层。
- 凹陷效果(Inset) :让表面向下切入,如沥青上的裂缝。
- 层偏移(Offset) :上下偏移图层位置,在处理 材质继承(Inheritance) 时非常关键,极大增加了材质的 通用性与灵活性 。
迭代过程
- 经过与美术的 大量迭代与测试 ,初始设计 在整个项目期间未做改动 。
- 教训:"迭代本身不是坏事,但 前期投入足够的设计时间 是值得的。"
高度图的具体应用
屏幕空间环境光遮蔽(Screen Space Ambient Occlusion)
- 传统 SSAO 仅使用 深度缓冲 + 法线 。
- 集成高度图后,即使是 平面几何体 ,也能生成更丰富的 AO 细节。
- 优势 :
- 响应 图层混合(Layer Blends) 的变化。
- 与其他几何体 相交时能正确交互 。
- 无需将 AO 烘焙到纹理中。
屏幕空间阴影(Screen Space Shadows)
- 砖块、窗户玻璃等都能投射出微小的 接触阴影(Contact Shadow) ,增加了 深度感与可信度 。
效果评估
- 坦诚地说,这两个效果在游戏实际运行中 大多数时候非常微妙 ,视觉上不太显眼。
- 但由于高度图已 深度集成在管线中 ,这些效果几乎是 "免费的" 。
- 团队期望在 下一代硬件 上,能负担更多采样次数,使效果更加明显。
贴花系统(Decals)—— 最成功的应用
- Gameplay 驱动的贴花 (如 血液贴花 )可以读取下方表面的高度图数据。
- 效果极为出色:
- 血池会 自然嵌入地毯纹理 ,并 避开掉落的表面碎片 (如天花板石膏块)。
- 同一套血液贴花在 地板、瓷砖、沥青、凸起瓷砖 等不同表面上都能 自适应整合 。
- VFX 团队接入高度图缓冲区非常简单,能 轻松利用 这一功能。
实时法线生成(Real-Time Normal Generation from Height Map)
核心算法
Normal=normalize(cross(ddx(h),ddy(h)))
- 使用 ddx / ddy 求导 + 叉积(Cross Product) 生成法线。
固有问题
- 此方法天然存在 多边形面片化(Polygon Faceting) 和 像素化伪影(Pixel Artifacts) ,这是数学本质决定的,无法完全避免。
实际应用:图层混合边界
- 唯一 无法预烘焙法线 的地方 = 图层之间动态生成的混合区域 。
- 通过 Border Blend(边界混合) 功能控制该区域。
- 混合区域的 高频噪声 天然地 遮盖了像素化伪影 ,因此效果非常好。
- 代码中通过
blend mask 参数限定只在 图层交界区域 生成法线,精确控制生效范围。
协作反思:成功与教训
成功之处
| 方面 | 评价 |
|---|
| 美术界面设计 | 巨大成功,前期设计充分,整个项目未做修改 |
| 系统整体设计 | 高度图深度集成管线的架构非常合理 |
| 贴花等特定用例 | 效果远超预期 |
失败与反思
- 屏幕空间阴影的原型开发 暴露了协作问题:
- 演讲者做了大量 原型工作(Prototyping) ,获得了正确结果。
- 但 高度优化的实现 涉及 极难的数学和编程 ,超出了技术美术的能力范围。
- 关键错误 :没有在早期与程序员达成共识—— 这只是概念验证(Proof of Concept) 。
- 如果一开始就明确定位,原型可以 做得更快 ,代码也可以 与主代码库隔离 。
- 频繁地 逐行请教程序员 反而造成了摩擦——程序员认为技术美术要么应该 独立完成 ,要么应该 直接交接 。
- 最终由程序员 Hawar 接手完成了 出色的最终实现 。
核心教训
技术美术做原型验证时,应明确边界:前期定位为"概念验证",隔离代码,减少对程序员日常工作的干扰;确认可行后及时交接给程序员做产品级实现。 结果可以一样好,但过程中的摩擦可以大幅减少。
湿润与雨水渲染系统
开发背景与团队状态
- 此阶段技术美术团队仍处于 "证明自身价值" 的模式中。
- 演讲者坦承:作为对高度图开发中过度依赖工程师的反弹,这次选择 几乎独立完成所有工作,不太寻求程序团队的输入 。
- 事后反思:这种方式 长远来看并不健康 ,但属于团队成长过程中的阵痛。
湿润系统基础
继承自《神秘海域4》的核心机制
- 核心思路:用 单一的湿润参数(Wetness Parameter) 驱动表面从干燥到积水的 完整渐变过程 :
干燥(Dry)→潮湿(Damp)→表面张力水膜(Clinging Water)→积水(Standing Puddle)
- 该参数会 同时影响所有 BRDF 参数 (颜色、粗糙度、反射率等)。
新挑战
- 《最后生还者 Part II》包含 大量雨天场景 和湿润表面,初始技术推进始于 巴黎游戏展(Paris Game Show)预告片 的制作。
湿润遮罩与流水动画
简化美术工作流
- 旧方式 :美术需要同时制作 高光遮罩(Specular Mask) 和 配套法线贴图(Normal Map) ,两者难以同步动画。
- 新方式 :美术 只需制作一张湿润遮罩(Wetness Mask) ,系统自动从中 派生所有所需数据 。
流水动画技巧
- 美术绘制一张 静态遮罩 ,标记水流路径(水纹/细流)。
- 引擎叠加一张 滚动的云纹理(Scrolling Cloud Texture) ,利用之前描述的 Flow 技术 进行交叉淡入淡出。
- 效果:水流在角色皮肤上 自然流淌并不断变化 。
高光法线系统(Specular Normal)
核心概念
- 标准做法 :法线贴图同时影响漫反射和高光反射。
- 新系统 :启用 Specular Normal 功能后,系统激活 不同的延迟渲染排列(Deferred Permutation) 和 不同的 G-Buffer 配置 ,将法线分为两套:
| 法线类型 | 用途 | 读取位置 |
|---|
| 漫反射法线(Diffuse Normal) | 控制漫反射光照、次表面散射等 | SSS Pass、最终延迟着色 |
| 高光法线(Specular Normal) | 控制高光反射 | IBL Pass、最终延迟着色 |
管线中的正确传递
- 次表面散射通道(Subsurface Pass) :只读取 漫反射法线 。
- IBL 通道(Image-Based Lighting Pass) :只读取 高光法线 。
- 最终延迟着色器(Final Deferred Shaders) :同时读取 两种法线 。
应用于皮肤上的水滴
- 对湿润遮罩施加 阈值(Threshold) 处理。
- 将结果缩放到 真实世界 ±10 cm 的高度图范围。
- 利用之前介绍的 从高度图实时生成法线 的技术,生成高光法线。
为什么需要分离法线?
- 如果高光和漫反射 共用同一法线 ,水滴在皮肤上看起来会像 血管/静脉(Veins) ,而非自然的 高光亮点 。
- 分离后,水滴只在 高光通道 产生凹凸效果,漫反射保持皮肤原始法线,视觉上自然得多。
水滴焦散与阴影模拟(Caustic Refraction & Shadowing)
物理原理
- 以 玻璃半球 为类比模型:
- 光线穿过水滴时,在 高光点 处能量汇聚(焦散高亮)。
- 在半球 对侧 形成投射阴影。
实现思路
- 已知当前像素的 渲染法线 和来自湿润遮罩的 高度值 。
- 利用这些信息 构建虚拟水滴的数学模型 。
- 由于 只能访问当前像素(无法读取相邻像素),需要进行 反向投影(Reverse Projection) ,推算最终的 折射光线方向 。
- 最终判定该像素应为 高亮区(Highlight) 还是 阴影区(Shadow) 。
代码质量评价
- 演讲者坦率地称这段代码是 "一个巨大的 Hack" 。
- 但强调这是一个 基于真实物理现象建模 的 Hack,尽可能忠实于实拍参考。
推广应用
- 控件被 通用化 后,应用于游戏中几乎所有表面:
- 积水(Puddles) 也得到升级:
- 积水底面使用 漫反射法线 (表现水下地面纹理)。
- 水面使用 高光法线 (表现平坦或波纹水面)。
- 差异虽细微,但 可感知 。
开发质量自评
| 评估维度 | 结果 |
|---|
| 代码质量 | 除焦散部分外, 整体编写较为干净 |
| 技术复用 | 高度图技术 得到高效复用 |
| 美术可用性 | 功能设计以 美术易用性为优先 |
| 高光法线系统 | 实现 高效 且 高度可扩展 ,积水即为扩展应用的典范 |
更多雨水和湿润相关技术可参见 Artem Kovalovs 在 SIGGRAPH 2020 的演讲 "GPU-Driven Effects of The Last of Us Part II" 。
渲染技术验证方法论
核心目标
- 物理基础渲染(PBR) 的终极目标是 尽可能匹配现实 ,即使永远无法完全达到。
验证手段
地面真值模式(Ground Truth Mode)
- 在渲染器中维护一个 昂贵但精确的参考渲染模式 ,用于对比检验实时渲染效果。
与现实对照
- 利用游戏角色 直接来自真人扫描 的优势(如角色 Abby 与其真人模特)。
- 在现实中精确搭建 匹配的摄影与灯光条件 :
- 测量 相机距离、高度 。
- 测量 光源强度、精确角度与高度 。
- 将引擎渲染结果与真实照片进行 逐像素对比 。
能量差异评估
- 评估正确性的方式:测量渲染结果与地面真值之间的 能量差异(正或负) 。
- 差异会随以下因素变化:
- 实际操作中 并没有量化测量工具 ,而是通过 目视对比 与 持续讨论 来驱动优化方向。
关于瑕疵(Artifacts)的重要原则
不连续性问题(Discontinuities)
- 需要特别警惕 空间上或时间上的不连续性 。
- 经典案例: 屏幕空间反射(SSR) 本身相当精确,但当它 回退到 Cube Map 时,如果两者 不匹配 ,会产生 极其引人注目的硬边 。
"蚊子效应"
- 硬边和局部高对比区域会创造大量 视觉焦点 ,像 耳边嗡嗡叫的蚊子 一样:
核心取舍原则
即使意味着理想情况下渲染精度略有降低,也值得去消除各类视觉瑕疵。
- 换言之: 感知上的正确性(Perceptual Correctness) 有时比 物理上的绝对正确性(Physical Correctness) 更重要。
眼睛着色器(Eye Shader)重制
渲染架构概述
眼睛的特殊渲染路径
- 在 Naughty Dog 引擎中,眼睛采用 前向渲染(Forward Rendered) ,但仍然 写入 G-Buffer 。
- 全屏通道(如 次表面散射、IBL、后处理 等)基于 G-Buffer 数据运作。
- 最终由一个 前向通道 读取这些缓冲区并计算最终光照。
- 该前向通道是 游戏中最昂贵的着色器 ,但由于眼睛在屏幕上 占比极小 ,实际帧率影响 微乎其微 (即使特写镜头也 低于 1 毫秒 )。
起点与问题
- 初版(公布预告片中 Ellie 的眼睛)虽然经过精心制作,但看起来 有些卡通化(Cartoony) ,且只在 特定光照和摄像机角度 下效果好。
- 目标:实现更加 动态、栩栩如生 的眼睛。
研究方法论
参考资料
- Jorge Jimenez 的 "Next Generation Character Rendering" 论文是绝佳起点。
- 团队还进行了 自己的摄影参考拍摄(Photo Shoot) 。
关键方法论建议
像科学家一样工作 :提出假设 → 设计实验 → 测量结果 → 发现意外的微妙差异。
- 网上有大量眼睛参考图,但 自己拍摄参考 不可替代。
- 对 任何物理现象 的分析都应遵循此流程:仔细测量和观察是理解效果的关键。
- 意外的微妙发现 往往是推进技术的真正动力。
实现策略
- 将眼睛着色分解为 所有微观特征(Micro Features) ,逐一实现并叠加。
- 大部分功能直接参考 Jorge 论文实现,演讲仅聚焦于 与其不同或改进的部分 。
核心渲染特性
屏幕空间阴影——眼睑与睫毛投影
实现方式
- 采用 暴力光线步进(Brute Force Ray March) 方法。
- 硬编码步进距离 ,采样 不透明 + Alpha 深度缓冲区(Opaque + Alpha Depth Buffer) 。
- 从该深度缓冲区中获取 睫毛的阴影信息 。
优势
- 比业界常见方案(动画平面 或 查找纹理 / Lookup Texture )可靠得多 。
- 能捕捉 眼睑形状 和 眉毛位置 的微妙差异(如 Joel 的特写镜头)。
扩展应用——IBL 遮蔽
| 用途 | 方法 |
|---|
| 高光 IBL 遮蔽 | 沿 摄像机反射向量(Camera Reflection Vector) 进行光线步进 |
| 漫反射遮蔽 | 直接读取 现有的屏幕空间环境光遮蔽(SSAO)缓冲区 |
焦散光折射(Caustic Light Refraction)
实现思路
- 本质上是一个 临时性函数(Ad Hoc Function) ,但经过精心调校以 尽可能匹配参考 。
- 利用 双法线系统 :
| 法线类型 | 作用对象 |
|---|
| 漫反射法线(Diffuse Normal) | 照亮 虹膜内表面 、驱动 次表面散射 |
| 高光法线(Specular Normal) | 用于 角膜外表面 |
- 这样设计的好处:IBL 反射等系统 无需了解眼睛着色器的任何特殊知识 ,只需处理 G-Buffer 中的数据即可。
实现质量的坦诚评价
- 焦散效果的代码 确实很 Hack 。
- 但由于渲染被拆解为 极其细粒度的真实世界现象 ,即便是 Hack 也可以 独立测量正确性 并 独立调优 ,不影响其他元素。
角膜缘(Limbus)——虹膜周围的暗环
物理原理
- 角膜缘 不是眼睛颜色的一部分 ——它是 角膜折射 将光线聚焦偏离边缘所产生的视觉效果。
- 常见做法是直接 画进漫反射纹理 ,但这无法正确响应光照变化。
参考观察
- 当光线 正面照射 时,角膜缘 几乎消失 。
- 当光线以 掠射角(Glancing Angle) 照射时,角膜缘 非常明显 。
实现方式
- 提供角色美术对 角膜缘强度(Limbus Intensity) 的控制(个体差异大)。
- 对环境光照:在 半球上 8 个方向 暴力计算角膜缘强度,然后取平均值。
- 确保美术控制在 所有光照类型 下给出 一致的视觉结果 。
- 曾考虑直接应用于 球谐函数(Spherical Harmonics)查找 ,但其带来的微妙提升 不值得额外开销 。
泪线(Tear Line)
问题性质
- 与其说是模拟物理能量传输,不如说是 用实用方案解决实际问题 。
实现方式
- 使用 G-Buffer 贴花(G-Buffer Decal) :一块附着在眼睑上、随眼睑动画的几何体。
- 对 G-Buffer 进行 多采样模糊(Blurred Multi-Sample) 。
- 混入一个 凹凸不平的水面法线(Lumpy Water Normal) 。
- 将结果 写回 G-Buffer 。
影响通道
| 通道 | 是否受影响 |
|---|
| 法线(Normal) | ✅ 主要效果来源 |
| 颜色(Color) | ✅ |
| 粗糙度(Roughness) | ✅ |
| 高光(Specular) | ✅ |
巩膜次表面散射修正(Sclera SSS Fix)
发现问题
- 在 掠射角(Grazing Angle) 下,巩膜(眼白)的次表面散射能量 不足 ,表现为眼白边缘只有一圈微弱的光环。
解决方案
- 问题并非代码错误,而是需要调整 次表面散射通道所使用的漫反射法线贴图 。
- 原来设定为 凸面(Convex) ,实际应为 凹面(Concave) 。
- 团队认为这是 物理上合理的解决方案,而非 Hack 。
- 关键启示 :如果没有自己拍摄参考,这个问题 不会被注意到 。
牙齿着色器(Teeth Shader)
- 将许多眼睛着色器的自定义技术 应用到牙齿上 ,牙齿同样采用 前向渲染 。
- 灵感来自 London Studio 的 James Anser 。
关键技术点
| 技术 | 说明 |
|---|
| 屏幕空间阴影 | 与眼睛类似的实现 |
| 自定义次表面散射 | 使用 更小的散射半径 ,并加入特殊处理防止 嘴唇光照溢出到牙齿上 |
| 微湿润法线(Micro Wetness Normal) | 源自 "Humanness" 论文中的技术 |
阶段性总结与团队变动
成果评估
- 前期研究(先行技术 + 自拍参考)极具价值,提供了 清晰的逐特征实现路线图 。
- 新眼睛着色器效果优秀,代码 健壮可靠 。
团队协作状态
- 技术美术团队 巩固了技术基础 ,交付了优质工作。
- 但状态是 "不妨碍程序员,但也并未真正协作" ——有进步,但还不够。
人事变动
- 另一位技术美术总监 Andrew Maximov 离职创业。
- 演讲者接管了其大量 工具与管线(Tools & Pipeline) 方面的职责。
- 招入 Steven Tang 继续推进着色器开发。
- 入职后数月进行 持续的代码审查(Code Review) ,将其提升到团队已达到的 代码质量与研究标准 。
逆反射眼睛技术(Retro-Reflective Eyes)
- 游戏中需要制作 标本狼的逆反射眼睛 ——许多夜行动物具有此特征,好的标本师也会重现这一效果。
- 人类眼睛着色器已基本完成,因此将此任务交给 Steven 作为 首个独立开发项目 。
动物眼睛的逆反射(Retro-Reflective Animal Eyes)
需求背景
- 游戏中某些场景(如博物馆)需要动物眼睛在强光下 发出诡异的光芒 ,营造恐怖氛围。
- 最直觉的做法 :给眼睛加一个 自发光分量(Emissive) ,用菲涅尔调制并绑定到手电筒强度上——但这 非常 Hack 。
科学原理
- 某些动物(如 狼、猫 )在视网膜后方有一层额外的反射层,称为 脉络膜反光层(Tapetum Lucidum) 。
- 该层将光线 沿原路反射回去 ,使光线 两次穿过视网膜 ,从而在暗环境中获得更好的视力。
- 我们看到的"发光眼"效果,本质上就是该反光层的 高光响应(Specular Response) 。
实现方案
- 理解了物理本质后,实现变得非常简单:
- 添加一个 高光分量 ,使用 光源方向作为法线 (模拟逆反射——光沿入射方向反射回来)。
- 用 虹膜区域遮罩(Iris Mask) 限制范围。
- 对照参考照片进行 调优 。
- 还叠加了 虹彩效果(Iridescence) ,使用后文介绍的 薄膜干涉(Thin Film Interference) 函数实现。
后续推广
- 团队非常喜欢这种诡异的发光效果,最终将其 扩展到所有感染者敌人 身上。
- 眼睛着色器在项目后期持续进行 微调 (如深棕色虹膜上焦散不够强等),但 核心技术一直稳定到项目结束 。
玻璃渲染技术(Glass Rendering)
概述
- 《最后生还者 Part II》中有 大量玻璃 ,形态各异。
- 核心策略:将技术做得 模块化、可复用 ,驱动游戏中所有玻璃需求。
四种核心玻璃渲染技术
预乘 Alpha(Pre-Multiplied Alpha)——继承自《神秘海域4》
- 高光分量始终 100% 存在 。
- 漫反射不透明度(Diffuse Opacity) 是可变的,用于表现玻璃上的 污垢、油漆 等。
屏幕空间折射(Screen Space Refraction)——继承自《神秘海域4》
- 使用 扭曲的 UV 坐标 采样屏幕缓冲区的扭曲版本。
- 扭曲程度由 玻璃的物理属性 决定。
- 适合 玻璃瓶 等物体。
模糊折射(Blurry Refraction)——新技术
- 在由 玻璃表面粗糙度 定义的锥体范围内,对屏幕缓冲区进行 时间抖动的多重采样(Temporally Jittered Multi-Sampling) 。
- 非常适合 毛玻璃/雾面玻璃 效果。
- 由 程序员 实现。
假室内空间(Fake Interiors)——新技术
- 大量建筑有 可见的室内空间 ,如果真正建模代价巨大。
- 解决方案:基于 单个四边形(Single Quad) 用着色器模拟完整的窗户与室内。
假室内空间系统(Fake Interior System)详解
单个 Quad 包含的内容
- 以下所有元素 全部在一个着色器中完成 :
- 百叶窗(Blinds)
- 后方房间 的视差深度
- 玻璃表面
- 破碎区域
技术组成
| 组件 | 实现方式 |
|---|
| 视差百叶窗 | 在玻璃后方 5–10 cm 处添加即时深度层 |
| 室内空间 | 使用 立方体贴图(Cube Map) 表示,灵感来自 Joost van Dongen 的 Interior Mapping 技术 |
| 屏幕空间阴影 | 裂纹玻璃的投射阴影 |
| 双法线系统 | 高光法线 用于玻璃表面,漫反射法线 用于百叶窗——比单法线效果好得多,比双通道光照计算便宜得多 |
立方体贴图生成
- 美术在引擎中 建模真实的室内场景 。
- 灯光师用 中性白光 通过 假窗口开口 照亮场景。
- 使用标准的 Cube Map 捕获管线 生成图像。
投影算法
- 与标准 Box Projection(用于 IBL 立方体贴图光照)原理类似。
- 关键改进:投影 完全基于几何体的 UV ,而非着色器内参数。
- 给予美术 极大的灵活性 ——可以自由调整室内空间的位置与缩放。
- 通过将控制绑定到几何体而非着色器,允许 同一场景中大量变化 。
渲染管线集成
- 窗户采用 延迟渲染(Deferred Rendered) ,尽可能 低开销 。
- 立方体贴图乘以 窗户表面上烘焙的环境光照 ,确保光照变化时 无需手动调整能量 。
- 使用 预乘 Alpha 技术进行混合。
- 立方体贴图数据 打包进 G-Buffer 的自发光通道(Emissive Channel) 。
- 完全破碎区域 的 环境光遮蔽设为零 ,这是延迟渲染器中的特殊处理——告知系统 不对这些区域进行高光反射 。
- 其余一切(粗糙度、高光、漫反射法线等)走 完全标准的渲染管线 。
可交互破碎系统
材质修改缓冲区(Material Modification Buffer)
- 在 屏幕空间 运作,计算时机在 深度缓冲区之后、G-Buffer 通道之前 。
- 玩家射击窗户时,生成一个 投射到表面的粒子 ,写入该缓冲区。
- G-Buffer 通道渲染时读取此缓冲区,决定 哪些区域应破裂 。
低频 + 高频混合策略
| 频率类型 | 来源 |
|---|
| 低频信息 | 材质修改缓冲区(射击产生)、美术手绘顶点色(预设破损)、世界空间随机噪声 |
| 高频细节 | 仅在低频遮罩的区域内 叠加裂纹细节 |
- 该缓冲区最初在《神秘海域4》中开发,在本作中 大幅扩展 了用途。
实际应用效果
- 在大多数关卡中,假室内效果 非常微妙 。
- 可以 极其靠近可玩空间使用 ,只要在 近战距离之外 即可。
雨天玻璃效果(Rainy Glass Effects)
效果组成
| 组件 | 技术 | 作用 |
|---|
| 屏幕空间折射 | 旧技术(《神秘海域4》) | 基础静态水滴外观 |
| 模糊折射 | 新技术 | 雾面玻璃感 |
| 动画雨痕(Rain Streaks) | 专用 Shader Package | 修改折射法线与模糊度 |
雨痕动画纹理通道设计
| 通道 | 内容 | 行为 |
|---|
| R(红) | 雨痕轨迹 | 将折射模糊度设为 0,遮罩掉静态水滴 |
| G(绿) | 引领雨痕的大水滴 | 将折射模糊度设为 0,修改折射法线 |
| B(蓝) | 雨痕留下的静态小水滴 | 不动画,但被 R 通道的雨痕遮罩 |
| A(Alpha) | ID 遮罩 | 用于 随机化动画时序 |
- 使用 4 个版本 的该纹理 叠加堆叠 ,提供足够覆盖和变化,避免明显的重复图案。
动画实现步骤
- 基础滚动 :在 UV 的 V 方向简单滚动。
- 速度随机化 :使用 ID 遮罩添加速度变化和时间偏移。
- 水平噪声 :添加水平方向扰动,使其看起来像真实雨痕。
时间方差(Time Variance)
- 水滴不应以 匀速 下落。
- 使用 单调递增的正弦波噪声 对时间进行扰动:
tvaried=t+A⋅sin(ω⋅t+ϕid)
- 效果:水滴时快时慢,模拟真实的 表面张力与重力 交互。
破碎玻璃的假厚度效果(Fake Thickness Effect)
实现原理
- 使用一张 玻璃 ID 遮罩纹理 确定哪些像素属于 截面(Cross-Section) 。
- 该纹理可在 Substance Designer 中使用 Flood Fill 功能轻松创建。
核心算法
- 使用 简单视差偏移(Parallax Offset) 对纹理采样 两次 。
- 如果两次采样的值 不同 ,说明视线向量穿过了一个 截面 。
截面着色
| 组件 | 方法 |
|---|
| 法线 | 将裂纹纹理的法线贴图进行 膨胀(Dilate) ,作为 漫反射法线 应用;高光法线保持不变 ,保证玻璃表面的连续性 |
| 内部反射 | 使用 漫反射法线 采样 环境立方体贴图 ,作为 自发光分量 添加到玻璃上,模拟内部反射 |
薄膜干涉(Thin Film Interference)
物理原理
- 常见于带 UV 镀膜 / 防眩光镀膜 的眼镜或相机镜头。
- 光线击中薄膜表面时:
- 部分光 从薄膜 顶部反射 。
- 部分光 折射进入薄膜,从 底部反射 后射出。
- 两束光线走过 略微不同的路径 ,产生 相位差(Phase Offset) 。
- 相位差导致 波长相关的干涉 ——不同角度和薄膜厚度下,不同颜色被 增强或抵消 。
Δϕ=λ2π⋅2ndcosθt
其中 n 为薄膜折射率,d 为薄膜厚度,θt 为折射角,λ 为波长。
渲染集成
- 实现为 常规高光计算之后的额外步骤 。
- 效果 微妙但可见 :在白色光源下,玻璃高光中出现 绿色、紫色 等色调。
- 同样用于前述动物眼睛的 虹彩效果 。
模块化与统一界面
关键设计原则
- 所有特殊功能(可破碎玻璃、雨痕、薄膜干涉等)的 界面保持一致 。
- 不仅适用于各种类型的玻璃,也适用于其他 Alpha 混合表面 (如 植被、头发 )。
- 一切都 嵌入分层材质框架(Layered Material Framework) :
- 部分常用功能打包为 Shader Package (如可破碎玻璃包)。
- 美术仍然可以自由叠加 污垢、湿润、喷漆 等标准图层。
目标达成
在 标准化最复杂的设置 的同时,给予美术 极大的创作自由 。
团队协作的成功体现
玻璃系统的分工
| 贡献者 | 负责内容 |
|---|
| Kov | 模糊折射 |
| Hawar | 多层折射技术 |
| Artem & Stephen Marandino | 玻璃与水的交互 |
| 技术美术团队 | 材质系统设计、Shader Package、美术接口 |
关系修复的里程碑
- 玻璃系统的开发被视为 程序团队与技术美术团队成功协作 的典范。
- 成功的关键不仅在于 共同完成的工作 ,还在于技术美术团队 知道何时退后一步 ,为程序员 留出空间直接与美术团队合作 。
- 演讲者总结:这是一段 漫长的旅程 ——无论是技术层面还是团队关系层面——但 付出完全值得 。
这是一个 真正跨学科协作 的范例——技术美术、图形程序员和 VFX 团队共同完成。
系统架构总览
整个雪地变形系统分为三个层次:
| 层次 | 负责团队 | 核心内容 |
|---|
| 粒子渲染目标(Particle Render Target) | 图形程序员 | 检测并记录足迹位置 |
| 视差遮蔽映射(Parallax Occlusion Mapping) | 图形程序员 | 实现几何级别的凹陷变形 |
| 细节增强与系统整合 | 技术美术团队 | 法线重建、边缘隆起、阴影、与高度图系统联动 |
第一层:粒子渲染目标(Particle Render Target)
- 由图形程序员 Artem Kovalovs 实现。
- 对每块可变形雪地网格,分配一个 粒子渲染目标区域 (可在场景中看到矩形区域与连接线)。
- 每帧执行流程:
- 从角色 膝盖到脚底稍下方 进行 网格射线检测(Mesh Raycast) 。
- 若射线命中雪面,将一个 足迹粒子 绘制到粒子渲染目标中。
- 渲染目标作为 纹理输入 传递给雪地着色器,告知着色器 在哪里进行变形 。
第二层:视差遮蔽映射变形(Parallax Occlusion Mapping)
- 由图形程序员 Vincent Markson 与 Artem 等人合作实现。
- 基本流程:
- 在着色器中 采样粒子渲染目标纹理 。
- 映射到 世界空间 。
- 使用标准 视差遮蔽映射(POM) 实现基础凹陷变形。
深度缓冲修正——关键细节
- 为了使变形后的表面与其他物体 正确相交 ,POM 必须输出 正确的深度值 。
- 实现方式:
- 计算变形后的 世界空间位置 。
- 转换为 屏幕空间深度 。
- 在 G-Buffer Pass 之前 ,通过一个 自定义深度像素着色器(Custom Depth Pixel Shader) 将其写入深度缓冲区。
第三层:技术美术团队的细节增强
变形法线重建
- 使用粒子渲染目标数据,通过 与之前介绍的导数法线相同的算法 构建变形法线:
Normal=normalize(cross(ddx(h),ddy(h)))
- 区别在于:这次计算不是在 屏幕空间 ,而是在 粒子渲染目标空间 中进行。
- 通过 增大采样间距 ,可以轻松 软化法线 ,避免 棱面化伪影(Faceting Artifacts) 。
边缘隆起效果(Raised Edges)
- 粒子写入渲染目标时形状为 锥形(Cone Shape) ,直接使用会导致变形看起来不自然。
- 解决方案:
- 使用一个 二次函数(Quadratic Function) 重映射锥形轮廓。
- 翻转并镜像 形状。
- 最终得到变形周围 平滑自然的隆起边缘 ——模拟雪被挤压后向两侧凸起的真实效果。
变形区域细节法线
- 使用粒子渲染目标作为 遮罩 ,在变形区域叠加 细节法线贴图 ,增加表面纹理细节。
变形投影阴影(Drop Shadow)
问题
- 视差效果仅在 G-Buffer Pass 和 自定义深度 Pass 中生效。
- 当阳光投射阴影时,阴影 Pass 看到的是 未变形的原始雪面 ,导致阴影不正确。
解决方案
- 完全关闭 雪地几何体的 阴影投射 。
- 使用基于 太阳方向的视差投影 添加 假阴影(Fake Shadow) 。
- 坦诚地说:这 仅适用于太阳光 ,但游戏中也确实只有这一种使用场景。
与高度图系统联动
- 变形区域的 高度图值 会相应更新。
- 效果:血池贴花只出现在凹陷的足迹内部 ,而非覆盖在未变形的雪面上——与之前介绍的血液-高度图交互系统完美联动。
系统化方法带来的"免费"效果
VFX Lead Evan Cook 说过:"一切都是系统化的(It's all systemic)。"
由于整个系统基于 统一的渲染目标方法 ,以下效果可以 低成本实现 :
- 变形处 露出雪下的泥土 。
- 角色在斜坡上滑行时在 泥地中留下痕迹 。
- 血液融化雪面 的特殊效果。
演讲者强调:"说'免费'当然不完全准确——美术投入了大量心血——但这种方法让实现过程 可行且无痛 ,这就是我们追求的工作方式。"
总结与未来展望
下一代的技术方向
当前成就的意义
- 这是第一次团队的 许多技术在物理上是正确的 ,可以 直接继承到下一代 ,无需重写。
- 这意味着团队可以将精力集中在 缺失的细节 上。
仍然缺失的要素
| 类别 | 示例 |
|---|
| 缺失的渲染特性 | 桃毛(Peach Fuzz) 、 局部光线弹射(Localized Light Bounce) 、 更精细的头发细节 |
| 存在但不够正确的特性 | 毛孔细节不足 、 高光响应不够准确 |
展望
- 下一代主机和 PC 的硬件能力将带来 质量的巨大飞跃 。
- 只要坚持 正确性(Correctness) 和 可复用性(Reusability) ,以及 健康的协作 ,就能充分利用新硬件。
核心哲学总结
基于物理现实,而非堆砌 Hack
"Recreate physical phenomena, don't just layer hacks."
- 优先级排列 :
- 最佳 :如果有真实公式(如 斯涅尔定律 / Snell's Law 用于折射),直接实现。
- 次优 :如果真实公式太贵,建立 Ground Truth ,用更廉价的函数 拟合(Fit) 。
- 底线 :视觉上对照 自己拍摄的参考 调优——绝不凭空编造。
系统化思维与良好代码
- 不要只盯着眼前的问题,要思考如何创建 互相构建、互相通信 的可靠且可扩展的 系统 。
- 美术界面要尽可能 简洁且强大 。
- 性能优化 不言而喻,必须贯穿始终。
提升团队,做桥梁而非墙壁
"Don't be a wall, be a bridge."
- 不要替美术与程序员对话 ——把他们直接联系在一起。
- 不要替程序员向美术团队解释功能 ——让程序员自己展示。
- 帮助每个人以 最佳方式展示自己的工作 。
Naughty Dog 技术美术团队概况
| 指标 | 数据 |
|---|
| 全职技术美术 | 约 8 人 |
| 偶尔贡献代码的人员 | 约 12 人 |
| 着色器代码量 | 48,000 行 |
| 脚本代码量 | 500,000 行 |
团队职责范围
- 帧率与内存优化
- 美术创作标准与规范 的制定
- 大量工具与脚本 的开发,简化美术工作流
- 支撑整个渲染管线的材质与着色器系统
致谢要点
- 图形程序团队 :提供了坚实的引擎基础,技术美术的工作本质上是在此基础上 添加额外细节 。
- VFX 团队 :许多效果的实现离不开他们的协作。
- 美术团队 :他们的创意 启发了大量功能 ,并将技术 转化为最终的游戏现实 。