aiQA
user
pbr和光追的关系是什么?
gemini
要彻底理清这两者的关系,我们可以用一句话来概括:PBR 决定了物体“表面是什么材质”,而光线追踪决定了“光从哪里来,又被挡在了哪里”。
它们在图形学中属于两个完全正交(互相独立)的维度。你可以把它们拆开用,也可以组合在一起用。
1. 核心定义拆解
-
PBR(基于物理的渲染):它是一种材质与着色模型(Shading Model)。
它关心的是微观层面的物理规律,比如能量守恒、微表面粗糙度、菲涅尔现象。它的工作是回答:“如果这里有一束光照到这个像素上,它应该反射出多少光?折射出多少光?”
-
光线追踪(Ray Tracing):它是一种可见性与光路算法(Visibility & Transport Algorithm)。
它关心的是宏观层面的几何相交。它的工作是回答:“这束光究竟有没有被墙挡住(阴影)?它在镜子里的倒影反射的是哪个物体?环境里四面八方的漫反射光是如何汇聚到这一点的?”
2. 四象限矩阵:它们的组合关系
因为它们是独立的,所以我们可以在渲染引擎中看到以下四种组合:
| 渲染管线架构 | 非 PBR 材质 (传统经验模型) | PBR 材质 (基于物理的模型) |
|---|---|---|
| 光栅化管线 (Rasterization) | 早期 3D 游戏 (如 CS 1.6, 魔兽世界): 使用 Blinn-Phong 光照,没有能量守恒,全靠美术画贴图来“假装”高光。 | 现代主流游戏 (如 绝地求生, 原神): 使用 PBR 材质,但光影和反射全靠 Shadow Map 和环境贴图(IBL)来“骗”视觉。 |
| 光线追踪管线 (Ray Tracing) | 早期图形学 Demo: 比如 80 年代经典的 Whitted 光追。镜面反射是完美的,但材质看起来像没有质感的塑料,因为没有引入微表面理论。 | 影视级/顶级画质 (如 电影特效, PBRT, 赛博朋克2077光追版): 路径追踪 + 真实的 PBR 材质,光和材质都遵循物理法则,达到照片级真实感。 |
3. 为什么它们是“绝配”?(从渲染方程看)
如果要用图形学最核心的渲染方程 (Rendering Equation) 来解释它们的协作关系,就一目了然了:
- PBR 负责了方程中的 \(f_r\) (BRDF):它精确计算了不同粗糙度、不同金属度的材质,是如何散射入射光的。
- 光线追踪负责了解这个积分 \(\int_{\Omega} L_i\):在实时光栅化中,为了解开这个庞大的积分,我们用了各种阉割版的近似(比如把环境光预处理成一张模糊贴图)。而光线追踪则是简单粗暴且正确地向四面八方发射无数条射线,把真实的 \(L_i\)(入射光)硬算出来。
当极其准确的材质(PBR)遇到了极其准确的光源(光追),结果就是逼近现实的画面。
💡 通俗的类比
- PBR 就像是“高质量的颜料和画布”。它保证了无论你怎么打光,这块金子看起来永远像金子,木头永远像木头。
- 光栅化 就像是“舞台布景的打光师”。为了省钱和快,他在金子旁边放个探照灯,假装这里很亮,但仔细看边缘没有阴影,镜子里的反射也是一张贴上去的假图。
- 光线追踪 就像是“真实的太阳光”。阳光自然地照在金子上,金子反射的光又照亮了旁边的墙壁,一切光影都是自然发生的。
针对你的引擎架构设计,如果你准备把 PBR 作为一个可选的 RenderPass,你打算如何处理环境光?是用预计算的 HDR 全景图(IBL)来给你的 PBR 材质提供基础照明,还是先用几个简单的点光源跑通材质的高光测试?
user
如果我希望在渲染器里把pbr和光追都做成可选的渲染方式,因为我需要用这个渲染器做作品集另一部分的程序动画,但程序化动画不需要也没必要用到光追和pbr,应该怎么组织?
gemini
这是一个非常经典且具有极高工业价值的引擎架构需求!在同一个渲染器中兼容“极简程序化着色”、“高质量光栅化 PBR”和“硬件光线追踪”,最核心的设计哲学就是“数据与渲染逻辑完全解耦”。
你需要将整个渲染器设计成一个“加工厂模式”。几何体和材质属性只是“原材料”,而具体的渲染管线是不同的“流水线”。
以下是无需代码的纯文字架构设计方案,分为四个核心模块:
1. 数据层:定义“原材料” (Scene Data)
在这一层,对象绝对不能知道自己将“如何被画出来”。它们只负责描述自己“是什么”。
- 渲染项 (Render Item):场景中的每一个物体都是一个 Render Item。它包含两个核心组件:几何数据(网格、顶点)和空间变换数据(矩阵)。
- 抽象材质描述 (Abstract Material):给每个 Render Item 挂载一个逻辑材质。这个材质只存储参数(如 BaseColor、Roughness、Metallic),而不绑定任何 Shader。
- 材质意图 (Material Intent):在材质中加入一个标签,表明这个物体期望的最高渲染级别(例如:
Require_Unlit,Require_PBR)。你的程序化动画生成的几何体,默认打上Require_Unlit的标签;而精美的展示模型打上Require_PBR。
2. 控制层:全局渲染主管 (Global Dispatcher)
这是引擎的大脑,负责读取用户的 UI 设置,并决定当前帧激活哪条“流水线”。
- 全局画质开关:维护一个全局状态,比如
CurrentEngineMode = MODE_BASIC | MODE_PBR | MODE_RAYTRACING。 - 降级机制 (Fallback):主管的核心逻辑。如果全局开关是
MODE_BASIC,但某个模型标签是Require_PBR,主管会强制忽略它的 PBR 需求,提取它的 BaseColor,将其“降级”分配给基础渲染流水线。
3. 执行层:多路渲染通道 (Render Passes)
这是龙书 DX12 概念大显身手的地方。你需要构建三个完全独立的渲染通道(Render Pass),每个通道内部管理自己的 PSO(管线状态对象)、根签名(Root Signature)和 Shader。
- 基础通道 (Basic Pass):
- 职责:专为程序化动画和 UI 辅助线服务。
- 配置:极简的 Vertex Shader 和 Pixel Shader,只计算基础的矩阵变换和纯色/顶点色输出。关闭复杂的深度测试或光照计算,追求极致性能。
- 光栅化 PBR 通道 (Raster PBR Pass):
- 职责:处理高质量的静态场景。
- 配置:挂载包含微表面模型公式的复杂 Pixel Shader,绑定环境光贴图(IBL)描述符表,可能还会包含一个前置的阴影贴图(Shadow Map)生成通道。
- 光线追踪通道 (Ray Tracing Pass):
- 职责:终极画质。
- 配置:调用 DXR 接口,构建底层加速结构 (BLAS) 和顶层加速结构 (TLAS),触发 Ray Generation Shader。
4. 运行时流转:一帧的生命周期 (Frame Flow)
当你的引擎跑起来时,每一帧的流程如下:
- 逻辑更新 (Update):CPU 计算程序化动画的逻辑,更新这些特定 Render Item 的顶点数据和矩阵。
- 收集与分拣 (Cull & Sort):
- 全局主管查看当前场景中所有可见的 Render Item。
- 根据它们的“材质意图”和“全局画质开关”,将它们分别扔进三个不同的篮子(队列):
Basic_Queue、PBR_Queue、RT_Queue。
- 分发绘制 (Draw):
- 阶段 A:命令列表绑定 Basic Pass 的 PSO。遍历
Basic_Queue,发出 Draw Call。(你的程序化动画在这里瞬间画完)。 - 阶段 B:命令列表切换到 PBR Pass 的 PSO。遍历
PBR_Queue,发出 Draw Call。(展示模型在这里被渲染)。 - (如果是光追模式,则跳过阶段 B,直接将队列送入光追流水线进行计算)。
- 阶段 A:命令列表绑定 Basic Pass 的 PSO。遍历
- 画面合成 (Present):将各个通道渲染的结果混合到最终的后备缓冲区上屏。
架构总结优势: 通过这种“分拣桶”的设计,你的程序化动画数据永远只会被送进 Basic Pass。无论你的 PBR 通道写得多么复杂,或者光追通道计算量多大,都完全不会影响到程序化动画的底层逻辑和运行效率。
对于你的程序化动画部分,由于网格形状可能会实时改变,你是计划每帧在 CPU 端计算顶点后重新上传给显卡(动态顶点缓冲区),还是打算利用计算着色器(Compute Shader)直接在 GPU 端生成网格?
user
如果我希望pbr实时渲染,有必要看pbrt吗?有什么推荐书目?
gemini
针对实时 PBR(基于物理的渲染)的需求,结论非常明确:你完全没有必要为了写实时 PBR 去啃 PBRT。
在图形学中,实时 PBR 和离线 PBR(PBRT 所讲的内容)虽然理论同源,但在工程实现上是两条完全不同的科技树。
- PBRT(离线)的核心是“算得准”:它通过发射几千条光线,用蒙特卡洛积分去硬解渲染方程(The Rendering Equation)。
- 实时 PBR 的核心是“骗得像”:为了在 16ms 内跑完一帧,前人发明了一系列极其聪明的数学近似(Approximations)和预计算(Precomputations),把原本极度复杂的积分强行拆解。
只有当你深刻掌握了实时 PBR 的“骗术”,却依然对某些物理现象的底层原理感到困惑时,PBRT 才是你查阅的“物理字典”。
为了你的作品集项目,你需要看的是那些专门讲“如何优雅地作弊”的资料。以下是为你精选的实时 PBR 必读/必看书目与文献:
1. 工业界“圣经”:Epic Games 2013 SIGGRAPH 演讲
这是现代几乎所有游戏引擎(UE, Unity, 甚至各家自研引擎)实时 PBR 的绝对蓝本。
- 文献名:Real Shading in Unreal Engine 4 (作者: Brian Karis)
- 为何必读:这篇文章提出了著名的 Split-Sum Approximation(拆分求和近似)。它教你如何把环境光照的复杂积分,拆分成两张可以预先计算好的贴图(预滤波环境贴图 + BRDF 积分贴图)。
- 对你的价值:你的 DX12 引擎里的 PBR Shader(特别是 IBL 基于图像的光照部分),核心代码就是直接翻译这篇论文里的数学公式。
2. 最佳工程实践指南:Google Filament 白皮书
Google 开源了一个专门针对移动端和实时的 PBR 渲染引擎 Filament,并附带了一份长达几十页的极致说明文档。
- 文献名:Physically Based Rendering in Filament (网页版可直接搜到)
- 为何必读:Epic 的论文偏理论,而 Filament 的文档是手把手教你写代码。它详细对比了各种不同的 NDF(法线分布函数)、几何遮蔽函数,并给出了极其优化的 GLSL/HLSL 代码片段。
- 对你的价值:这是你写 Pixel Shader 时的终极抄写模板,里面连除以零的各种边界情况(安全 Clamp)都帮你考虑好了。
3. 最友好的保姆级教程:LearnOpenGL (PBR 章节)
虽然书名带 OpenGL,但 PBR 的数学和着色器逻辑是跨 API 的。
- 位置:LearnOpenGL 官网 -> PBR 章节(国内有对应的中文站)。
- 为何必读:如果你直接看 Epic 论文觉得数学符号太晦涩,Joey de Vries 的这套教程用最通俗的人话把 Epic 的理论解释了一遍。
- 对你的价值:它提供了完整的从点光源 PBR 到 IBL(基于图像的光照)的代码实现。你只需要把它的 GLSL 代码脑内翻译成 DX12 的 HLSL 即可。
4. 字典补充:RTR4 (第 9 章)
- 《实时渲染(第四版)》的第 9 章(Physically Based Shading),专门梳理了微表面模型(Microfacet Models)的发展史。
- 当你遇到“粗糙度(Roughness)”、“金属度(Metallic)”、“反照率(Albedo)”这些概念不知道该如何传入 Shader 时,翻开这章。
💡 在 DX12 架构中的落地建议
为了在你的引擎中实现实时 PBR,你可以按照以下步骤逐步推进你的 PBRPass:
- 第一阶段:直接光照(Direct Lighting)
- 暂时不管复杂的环境光。只实现点光源/平行光下的 PBR 计算。
- 在 Shader 里实现 Cook-Torrance BRDF(主要是 D, G, F 三个项的计算)。
- 效果:你的物体在光照下会有正确的金属高光和非金属漫反射。
- 第二阶段:环境光照预处理(IBL 核心)
- 写一个离线的计算着色器(Compute Shader),或者直接利用工具(如 AMD 的 CMFT),将一张 HDR 全景图预生成所需的“漫反射辐照度图(Irradiance Map)”和“高光预滤波贴图(Prefiltered Map)”。
- 第三阶段:间接光照(Indirect Lighting)
- 在你的
PBRPass像素着色器中,采样第二阶段生成的贴图,加上基础的直接光照。 - 效果:绝杀!加上 IBL 后,你的模型(即便是最简单的球体)会立刻拥有以假乱真的电影级质感。
- 在你的
user
你认为这个架构是否存在实践意义?作为作品集如何?如果我希望渲染管线能够通过gui设置数据,这套系统边学边做有望在两年内做出来吗
gemini
这套架构不仅具有极高的实践意义,而且作为图形学岗位的作品集,它的含金量甚至会超过那些单纯堆砌了极其复杂数学公式的“玩具渲染器”。
以下是对这套方案的深度评估以及两年落地可行性的剖析:
1. 实践意义:无限逼近现代工业标准
你构思的这套“数据与逻辑解耦”的多通道架构,在工业界有一个非常著名的专业术语:数据驱动渲染管线(Data-Driven Render Pipeline)。 Unity 近几年主推的 SRP(可编程渲染管线)以及虚幻引擎底层的 Render Graph,其核心思想与你的设计完全一致。
- 现实痛点:在真正的游戏开发中,特效师需要极简的高性能 Shader 画粒子,而场景美术需要厚重的 PBR 画建筑。
- 你的解法:通过这套架构,你可以轻松证明自己不仅懂“怎么算光照”,更懂“如何将极其复杂的图形 API 封装成对开发者友好的系统”。这是高级引擎开发(Engine Programmer)的核心素养。
2. 作品集含金量:面试官视角的“杀手锏”
如果你的简历上写着“实现了一个 DX12 渲染器”,面试官通常会认为你只是照抄了龙书。但如果你加上“设计了多 Pass 架构,支持程序化动画的极简管线与 PBR/DXR 管线的动态降级与切换”,这会极大激发面试官的兴趣。
- 展现软件工程能力:图形学不仅是数学,更是复杂的 C++ 系统工程。这套架构证明你能驾驭复杂的内存管理、多态和状态机。
- 差异化竞争:绝大多数毕业生的作品集都是静态场景。你结合了程序化动画(动态几何体更新)+ 可选的高级渲染(PBR/光追),既有逻辑深度,又有视觉冲击力。
3. 两年时间规划与可行性分析
结论:两年时间完全足够,且这套架构的设计非常契合保持专注和正向反馈的需求。
由于整个系统是模块化解耦的,你不需要憋一个大招,而是可以采用“敏捷开发”,让每一步都有立竿见影的视觉效果:
- 前 3 个月(地基与极简通道):
- 彻底搞定龙书前 12 章。
- 搭建好
Basic Pass。 - 里程碑:将你的程序化动画算法接入进来。此时你拥有了一个性能极高、可以在屏幕上跑动复杂程序化骨骼/多足虫的引擎。这会给你巨大的成就感。
- 第 4-9 个月(GUI 与光栅化 PBR):
- 接入 GUI 库。
- 学习 Epic 或 Filament 的论文,在单独的
PBR Pass中实现光栅化微表面模型和 IBL。 - 里程碑:通过 GUI 拖拽滑块,屏幕上的金属球能在粗糙和光滑之间实时变化。程序化小虫在 PBR 场景里穿梭。
- 第 10-18 个月(光线追踪通道):
- 这时候你的 C++ 引擎框架已经非常稳固了。你可以开始啃 DXR 的官方文档。
- 由于架构解耦,你只需新增一个
RayTracing Pass,把原有的几何数据喂给加速结构即可。
- 最后半年(打磨与性能分析):
- 处理多个 Pass 之间的资源屏障(Resource Barrier)切换。
- 使用 PIX 等工具抓帧,优化显存。
4. GUI 方案的最佳实践
既然希望通过 GUI 设置渲染管线数据,在 C++ 和 DirectX 12 的生态中,Dear ImGui 是绝对的工业标准。
- 它是纯 C++ 编写的即时模式(Immediate Mode)UI 库。
- 接入极其简单,不需要学习复杂的事件回调机制。
- 你可以用不到 10 行代码画出一个带有“渲染模式下拉菜单”、“粗糙度调节滑块”、“灯光颜色拾色器”的控制面板,这些滑块直接绑定到你渲染器的 C++ 变量上,实现实时画面反馈。
针对这套蓝图,既然你希望通过 GUI 来控制系统,你打算让 GUI 只作为引擎视口上的一个“悬浮调试面板”,还是想把它做成类似 Unity/虚幻那样,左边是场景树、中间是渲染画面、右边是属性面板的“全功能编辑器”布局?