BlueRoseNote/07-Other/简历/图形学细节.md
2023-06-29 11:55:02 +08:00

173 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## RDG
### FrameGraph
首先需要了解Frame Graphe的设计思想为了速成看了知乎大佬 奔驰 的文章。但也因为速成必然会在一些地方有所误解还请见谅。这里说一下我的理解Frame Graphe思想可以理解为一帧中执行逻辑的图没有限定是渲染还是Gameplay逻辑但不管怎么说其重点在于图。
大致操作为将逻辑以最小功能为标准封装成单独的PassPass与Pass之间是变量或者可以理解为资源的传递的关系因此就可以把整个逻辑关系转换成一个Graphe。
UE4的RDG全名为Render Dependency Graph感觉是为了能更好的管理资源的加载回收尤其是RT拯救一下显卡上珍贵的显存以及IO带宽。同时方便程序员理解代码不会写出毛线团一样的代码。至于生成的图没有看过在哪估计在4.25加在Insight调试系统里吧。
### 大致流程
通过FRDGBuilder对象构建RDG渲染流程。之后塞入定义的RDG Uniform以及Shader后运行这个流程。RT会使用外部的IPooledRenderTarget接口取得比如各种GBuffer当然也可以自己创建之后绑定到RDG Uniform中的RenderTargets[0]数组中。最后根据是ComputShader还是PixelShader选择分发或是绘制即可。但源码里也没有RDG的PixelShader的代码95%都是ComputeShader的经过试验RDG的PixelShader的使用方法还是和旧版的GloalShader比较像的。
既然说到这个,之前我也是看了虚幻开放日的技术分享,知道了两者的区别。
### ComputeShader与PixelShader对比
ComputeShader对于PixelShader的优势
1. PixelShader只能处理当前ShaderComputeShader是任意位置可写。可以用于编写屏幕空间反射等需要将效果写入任意位置的效果。
2. 可以更好地利用显卡的并线单元。
3. 共享内存:举个例子模糊、等需要多次采样各个像素的算法,使用共享内存就可以减少采样次数与消耗。
PixelShader对于ComputeShader的优势
1. PixelShader可以预加载贴图并且缓存UV使得读取贴图的效率会非常高。而ComputeShader需要计算出UV所以做不到这点。
2. PixelShader支持FrameBuffer压缩减少带宽压力。
3. PixelShader支持更多的贴图格式。
ComputeShader还存在无法读取UAV比如把RT转化成SRV后才能读取问了EPIC的luoshuang说是历史遗留问题UE5会解决。
## 制作玉石效果
使用寒霜的FastSSS方案这里我下载了演讲的PPT。厚度贴图可以使用Substance Painter烘焙。算法是反转法线后使用AO算法在像素对应的三维坐标球形区域内生成若干采样点计算模型内部的点与总点数的比。之后就是直接套寒霜公式了。
## 光线追踪
《Ray Tracing in One Weekend》只是尝个鲜学习《Ray Tracing from the Ground Up》后拥有了一个基础的Ray Tracing框架。然后就是PBRT了相当不错的教科书。因为单线程渲染效率太低所以使用了直接使用Inter的TBB库但最后发现写的渲染器
会出现样本混乱的情况的。同时因为没有写并行库的基础所以之后的后面几章就没有去写代码了。如果有时间会去看《c++并发编程实战》的英文版来学习并行编程。
### PBRT
1. pbrt采用了FLOAT宏来调整浮点类型不过我记得VS的设置就可以直接调整。并且手动实现了EFLoat类来消除浮点数在四则运算后积累的误差。
2. pbrt采用c++11的线程编写没使用任何并行库。
3. 实现了一个场景描述文件格式可以将dcc软件制作的场景导入渲染。
### 一束光线
我们从眼睛中看到的图形可以理解为视觉细胞接收到场景中辐射与反射的光辐射信息的结果光线追踪就是计算机通过模拟这一过程所发明出的算法。根据光的波长不同将其排列成为光谱。但受限于人眼感光细胞人眼无法看到所有颜色对于可见光人们建立了不同色域范围的色彩标准。常用的是rgb、sRGB等。
#### 光源
PBRT为了将光谱值转换为RGB值实现了SampledSpectrum采样频谱与RGBSpectrumRPG频谱这里我没看懂好像是通过对3条曲线采样求积分得到3轴的比值。
#### 采样
除非直视光源不然人眼接收到的光全都是经过N次反射的因为我们可以把人眼接收到的图像理解成一个N阶多项式方程。同时这也相当于将一个自然现象模拟问题转化为一个数学问题可以用其他的数学工具来解决问题。但该方程无法直接求解所以会使用蒙特卡洛方法求近似值。
#### 蒙特卡洛方法
是一种以概率统计理论为基础的数值计算方法。它的核心思想就是使用随机数(或更常见的伪随机数)来解决一些复杂的计算问题。通过对大量抽样样本进行统计,计算出其分布规律。
概率密度函数 pdf 一个描述这个随机变量的输出值,在某个确定的取值点附近的可能性的函数。
累积分布函数 cdf 是概率密度函数的积分能完整描述一个实随机变量X的概率分布。
有关抽样:
#### 逆转法
#### 舍选法
某些函数可能无法通过对其进行积分从而获得pdf或者无法通过计算获得逆cdf。舍选法是一种无需进行以上任意一个步骤就能根据函数分布生成样本的技术。本质上它是一种投飞镖法假设我们想从某个函数f(x)中抽取样本但是我们有一个pdf p(x)满足f(x)< c p(x),假设我们知道如何从p中获取样本
这个过程反复选取一对随机变量(X,ξ)如果点(X,ξc p(X))是在f(X)下面,那么接受样本X否则它将被拒绝并再次选取一个新的样本对这个方法的效率取决于f(x)与cp(x)的接近程度越相似收敛地越快而且适用于任意维度的函数
#### 重要性采样
选择一个与目标概率密度函数具有相同形状的分布函数进行抽样来减少方差形状越接近收敛越快Raytracing in weekend中对方形面光源运行了重要性采样
#### 分层采样
对采样区域进行分割各个子区域单独生成样本
#### 低差异序列
低差异序列可以非常高效的生成分布非常均匀的高质量样本集合相比伪随机数极大的提高蒙特卡洛积分收敛的效率并且它们的实现都不复杂
- Van der Corput根据底数将指定长度的正整数序列转换为指定进制的数序列之后以小数符号为分界线将每个数左边翻转到右边去
- HAMMERSLEY 哈默斯利使用底数为 样本序号/样本总数 的Van der Corput序列
- Halton 霍尔顿使用底数为质数序列的Van der Corput序列
UE4中的TAA好像就是用的低差异序列生成的样本
#### 使用均值样本会产生 混叠现象,也就是摩尔纹
在信号处理以及相关领域中走样混叠在对不同的信号进行采样时导致得出的信号相同的现象它也可以指信号从采样点重新信号导致的跟原始信号不匹配的瑕疵它分为时间走样比如数字音乐以及在电影中看到车轮倒转等和空间走样两种摩尔纹)。这里我们不详细展开
#### 采样器基本原理
事先生成若干组采样点样本之后进行乱序操作在进行逐像素采样时使用伪随机的方式选取随机序号的采样点组
#### 抗锯齿
因为场景的定义在三维空间中是连续的而最终显示的像素则是一个离散的二维数组所以判断一个点到底没有被某个像素覆盖的时候单纯是一个或者没有"问题丢失了连续性的信息导致锯齿
SSAA超采样抗锯齿高分辨渲染之后取平均值结果
MSAA在光栅化阶段判断一个三角形是否被像素覆盖的时候会计算多个覆盖样本Coverage sample最后根据权重样本占比所在的片元进行着色不兼容延迟渲染管线
FXAA边缘检测抗锯齿是一种后处理抗锯齿技术
TAA时间抗锯齿将采样放到时间轴上的抗锯齿技术对一个像素使用抖动效果之后再将所有的采样混合起来他需要解决判断每帧中这个像素的移动位置但在一些运动较大或者帧数较低的情况会出现 重影的问题
#### 贴图采样
- 双线性插值
- ISOTROPIC TRIANGLE FILTER 各项同性三角形过滤 然无法生成高质量的结果但速度比较快该滤波器因为各项同性的关系不支持非正方形或非轴对称的范围该滤波器的主要缺点是在斜角度观察纹理时图像容易变模糊因为不同的角度会导致采样率不一致
- ELLIPTICALLY WEIGHTED AVERAGE 椭圆权重均值
#### 偏差分析与重采样
没学过相关知识无法继续
#### 加速结构
如果光线每次与物体交互都需要遍历所有三角形那效率将会非常低为了提高求交速度我们可以在渲染前实现构建加速结构常用的有BVHKD
BVH
1. 计算每个图元的边界信息并且存储在数组中图元号包围盒以及中心点
2. 使用指定的方法构建树中间对半切的方法SAH首先计算图元位置将其分配到12个桶中并且计算每个桶最大边界盒再遍历每个桶边界盒的Min与Max坐标计算最佳切分点通过 切分后两个边界盒的表面积/当前包围盒的表面积来计算求交效率子图元中质心距离最大的轴向作为分割方向
KD树对3个轴的所有的切分方案进行尝试最终计算出最优的空间分割方案
KD树的分割每个轴遍历所有分割方案与BVHSAH分割每个轴12次分割更加精确BVH保证每个图元只有一次引用内存占用较少构建较为简单而KD树并不保证所以内存占用较多因此KD树的求交效率要比BVH好也导致了渲染时需要花费比BVH更多的时间在构建KD树上 同时KD树在求交时会计算与光线与分割面的相交位置是否在[min,max]中来判断是否需要与茎节点中的两个节点一一求交以此来减少求交计算量而BVH通过深度优先遍历树进行求交的 总结BVH是基于物体分割的KD数是基于空间分割的
早几年NVIDIA研发出将两者结合的方案SBVH这种算法可以节约因为图元分布大小不均匀而造成的BVH树求交效率低下
1. 找到一个对象分割候选者使用SAH算法构建一个BVH
2. 找到一个空间分割候选者类似构建KD树算法
3. 选择获胜者基于SAH选择消耗最小的作为最后结果如果不满足叶子节点生成条件则继续分割
我记得是前几次进行空间分割后续使用对象分割
### 材质模型
接下来就是处理光线与物体交互的结果了PBRT把材质分开金属非金属与半导体其中半导体较为复杂Pbrt里没有介绍
根据材质性质不同可以分为一下表面分布函数
BRDF双向反射分布函数在单位微表面上反射辐亮度与入射辐射照度的比值
BTDF双向透射分布函数在单位微表面上折射辐亮度与入射辐射照度的比值
与两者结合的BSDF对于半透明材质则使用BSSSDF双向表面散射分布函数
#### 微表面模型
本来对于一个不确定表面可能需要使用采样要求积分因为物体的微观表面参差不齐无法通过分析的方法精准模拟但微表面模型假定物体由大量微小的绝对光滑表面组成之后就可以根据统计学计算出模拟出看上去正确的结果
现在用得较多的Burley模型迪士尼模型也是UE4使用的就是基于这个微表面模型
#### BRDF公式
对于各项同性的BRDF公式就是 漫反射 +菲尼尔函数 * 法线分布项 D * 几何项G/(4 cos入射角 * cos出射角)
Cook-Torrance
##### 菲尼尔
- 一般都会使用近似近似函数Schlick施利克
- 菲涅尔方程描述了光线接触到表面后反射与透射的比它实际上Maxwell方程在光滑表面上的求解 因为在现实环境中光的偏振现象较少所以在PBRT假设光不偏振
- 一般情况下计算计算机图形学中的常见操作都会忽略色散现象以此极大地简化光线传输计算色散折射率随着光的波长而变化)。
##### 微表面法线分布函数 (法线分布项 D)
- 法线分布函数由粗糙度决定主要影响高光
- BeckmannSpizzichino贝克曼-斯皮兹奇诺
- Phong
- TrowbridgeReitz特罗布里奇 瑞兹ggx
- 迪士尼改进了 TrowbridgeReitz 将其命名为GTR
##### 几何衰减因子Shadowing和Masking几何项G
- Smith阴影函数
- 迪士尼对Smith 改造smith-ggx
##### 漫反射
- pbrt中使用 ORENNAYAR奥伦-纳亚尔漫反射模型基于微表面模型
Raytracing in weekend会使用LAMBERTIAN漫反射 辐射度/π 作为漫反射项即不论任何角度都会反射出一样的辐射度
Lambert漫反射模型在边缘上通常太暗Disney开发了一种用于漫反射的新的经验模型以在光滑表面的漫反射菲涅尔阴影和粗糙表面之间进行平滑过渡思路是使用了2个Schlick Fresnel近似相乘作为调节因子
##### 测量BRDF
pbrt中还介绍了一种通过测量来拟合brdf的方法ff15中用到这种方法
##### BTDF
没看过应该乘以 菲尼尔来计算的
##### BSSDF
没看过UE4好像通过生成均值采样点之后再通过距离进行近似计算的
##### 迪士尼模型
根据透明度参数对透明渲染结果与绝缘体渲染结果混合之后再根据金属度与金属渲染结果混合
### 路径追踪
从摄像机发射采样光线最后把这条光线若干次反射过程中结果累加起来
### 优化
#### 光子映射
通过让光源发射光子来生成光子贴图这样就能让收敛速度变快
#### 双向路径追踪追踪
同时从光源与摄像机发射采样光线一起构建光路之后将各个反射点直接连接起来这样就能快速构建多条光路了大大加快收敛速度当然这些光路需要进行可见性测试