文章目录
- 前言
- 一,Ambient Occlusion环境光遮蔽
- 1.1 Precomputed AO
- 1.2 Screen Space Ambient Occlusion(SSAO)
- 1.3 Horizon-based Ambient Occlusion(HBAO)
- 1.4 Ground Truth-based Ambient Occlusion(GTAO)
- 1.5 Rat-Tracing Ambient Occlusion
- 二,雾效
- 2.1 Depth Fog
- 2.2 Height Fog
- 2.3 Voxel-besed Volumetric Fog体素化雾效
- 三,Aliasing抗锯齿
- 3.1 超采样方法SSAA、MSAA
- 3.2 Fast Approximate Anti-aliasing(FXAA)
- 3.3 Temporal Anti-aliasing(TAA)
- 四,后处理
- 4.1 bloom
- 4.2 Tone Mapping
- 4.2.1 Filmic s-curve tone-mapping
- 4.2.1 ACES
- 4.3 Color Grading
- 五,Rendering Pipeline渲染管线
- Tile-Based Rendering(Forward+)
- cluster based rendeing
- Visibility Buffer
- 挑战
- 六,Frame Graph/Render Graph
- 七,Render to Monitor:V-sync、G-sync
- QA
前言
- 老师课前寄语:
很多同学表示课程算法两太大听不懂,老师表示games104定位是一个通识课,因为20节课不可能讲清楚游戏引擎的全部内容,因此本门课程的核心是:帮助大家建立主流方法概念和知识体系,公式看不懂也没关系,重要的是思想,以便于未来举一反三。(比如老师上学时读论文,可能一天只能读一个算法都读不懂,但如果有人能提前指出这篇论文的核心点是123的话,读论文就能效率很多,本门课程就起到一个知识总结的作用)
一,Ambient Occlusion环境光遮蔽
1.1 Precomputed AO
烘焙的AO贴图,直接加到渲染光照里:开销很小,但是效果固定(静态)不自然
1.2 Screen Space Ambient Occlusion(SSAO)
利用深度图,在视角空间下的模型表面的给定半径中随机采样N个点,筛选其中深度比Zbuffer更近的点作为可见点,用可见点比例近似为ao,可见性 A ( p ) = 1 − O c c l u s i o n N A(p) = 1 - \frac{Occlusion}{N} A(p)=1−NOcclusion
问题:正常受光面是半球面,按照半径采样肯定至少有一半采样点在不可见的地方,因此不合理
- 所以有了SSAO+:只采样半球面,修复了上边说的逻辑不合理问题。
1.3 Horizon-based Ambient Occlusion(HBAO)
使用深度图作为heightfield图得到周围立体高度,在用ray-marching思想向周围探索最大仰角,将天顶可见范围作为可见性。同时增加attenuation function: m a x ( 0 , 1 − r ( θ ) R ) max(0,1-\frac{r(θ)}{R}) max(0,1−Rr(θ))利用设置的距离R来截断影响系数,减少远处的影响。
这里实现的时候有一些巧思,mark一下
问题:来自四面八方不同角度的光的贡献值实际上是不一样的,类似pbr的F项,天顶来的光和侧边来的光反射强度不同,因此计算有错误
1.4 Ground Truth-based Ambient Occlusion(GTAO)
加入了cosine factor,去掉了attenuation function,加入了多bounce的快速近似。
怎么近似多bounce的呢:根据不同的ao值对大量数据进行分析,将多bounce结果与ao值的曲线拟合为一个3阶多项式方程,其中ρ是albedo,Vd是单次ao,因此GTAO的结果是有颜色的
1.5 Rat-Tracing Ambient Occlusion
(RTX)从屏幕每个像素casting rays去看其有没有遮挡,使用RTT硬件和TAA思路加速,远处1spp(sample per-pixel),近处细节2-4spp。是未来发展方向,值得关注
二,雾效
2.1 Depth Fog
简单有效常用,三种模式,很多引擎内置比如unity
2.2 Height Fog
但真实的雾是气溶胶,是与高度相关的,比如爬山时山脚有雾山顶没有的现象。因此Height Fog假设低于某高度时fog都是最大值,但高于某高度时呈指数递减。
那么从高处看向低处的fog内的物体时,就需要积分。这里简化为对fog密度进行积分,并且是e的次方形式,可以求出解析解
2.3 Voxel-besed Volumetric Fog体素化雾效
可以实现雾气的丁达尔效果。将相机空间整体进行体素化,并且是以视锥划分的体素,可以做到近处细远处粗;计算方法与上一节计算云和多重散射的原理一样。
并且在划分体素时,体素大小应该与屏幕分辨率成比例,方便显示的连续性
三,Aliasing抗锯齿
- 造成锯齿的三种主要原因:
- 几何原因,比如边的采样
- 纹理采样
- 高光采样(高频信号的低频采样)
3.1 超采样方法SSAA、MSAA
SSAA全部4倍采样,MSAA先采样深度判断是否为边缘,边缘再4倍shading
问题是代价昂贵,用得少了;并且现代游戏经常三角形比像素还多,也不适用了
3.2 Fast Approximate Anti-aliasing(FXAA)
自己做过相关工作就简单记了:图像处理方式,通过亮度找出边缘,计算边缘offset,处理边缘像素和offset像素再blend。
效果好速度快,现代显卡一般集成了
3.3 Temporal Anti-aliasing(TAA)
具体可以去看202课程
目前游戏引擎主流算法。但是有时会出现拖曳残影等问题
四,后处理
老师:后处理就是一整个美颜相机
- 后处理两类目的:
- 让物理更加真实正确
- 风格化表达
4.1 bloom
现实世界中为什么有光晕呢?有的说人眼和相机一样不能完美的聚焦到一个焦平面上,会产生一种发散;也有的说人眼晶状体是一种半透明材质,光线进入会产生散射。
- 实现过程:
- 通过Luminance计算亮度(屏幕空间)—现在很多hdr的强度很大,有时会选择平均光场亮度计算
- 降采样几层
- 从最底层开始每一层高斯模糊后叠加至上一层----这个叠加的权重每个引擎都不一样,跟美术表现相关
4.2 Tone Mapping
比如大礼堂窗子附近非常亮,里边非常黑,这时拍照常常过亮或者过暗,这时在引擎中就需要Tone Mapping来调整曝光曲线,其实就是把HDR的图片信息映射到普通LDR的图片中,使屏幕效果更接近人眼效果,如下图
4.2.1 Filmic s-curve tone-mapping
能实现电影质感的曲线,用曲线拟合实现,shader如下
4.2.1 ACES
美国电影学院基于经验提出的曲线,优化了最终颜色被投入到各种不同显示终端的步骤(HDR和非HDR显示器、电影院等)
各个曲线对比:
4.3 Color Grading
就是美颜相机的LUT图调色
- Lookup Table(LUT):记录每一个颜色remap后的颜色,相当于吧3dTex拍平成2dTex不需要很精细,中间颜色插值计算即可。
性价比超级高,游戏表现的重要环节!!!
五,Rendering Pipeline渲染管线
流水线处理流程,图程面试必考,参考别的大佬笔记的管线知识点梳理细说图形学渲染管线
- 透明度排序:在现代游戏引擎中是非常难的事情
- 延迟渲染高显存问题:Tile-Based Rendering(移动端)
Tile-Based Rendering(Forward+)
- 将画面分为小块进行渲染
- Light culling By Tiles ,因为画面分为小块,所以光照效果的渲染也可以以小块为单位,单块内只循环涉及到的光源
- Depth Range Optimization ,光源的渲染也考虑深度范围(距离),剔除超出光照范围的tile
移动端友好,PC也可
cluster based rendeing
进一步,不止屏幕分tile,视锥空间z向也分tile,分成椎体,然后分别计算对light的可见性
Visibility Buffer
上述方法都是把信息存在了Gbuffer里,但其实可以把几何信息和材质信息剥离出来,用Vbuffer保存几何信息,也可以用来反向查找对应的渲染信息。
- 为什么要这么做呢?
- 现代引擎中几何密度非常高,甚至超过像素,使用Gbuffer储存会浪费大量的几何overdraw(earlyZ);
- 并且大量采用Gbuffer效率低,而Vbuffer及其ID效率非常高(同时自己写的光栅化比硬件光栅化效率更高)(需要dynamic indexing硬件)----没听懂啊
- Gbuffer种材质默认是一致的,而Vbuffer可以只保留用到的材质,并且材质更丰富
「nvidia 的Texture space shading(TSS)中有类似思路,直接在Texture上进行着色,然后再光栅化,将着色与分辨率、几何复杂度、帧率解耦—资料来自Texel Shading」
挑战
比如UE的引擎算法非常复杂,各个算法之间怎么work的,是一个很大的挑战:
- 不同模块相当于积木,应对不同的复杂项目需求要搭建不同的积木塔造型
- 很多计算需要消耗的buffer内存的时间远小于一帧,可能是中间值应该被释放掉的,但没有精密的内存管理时很多显存会被浪费掉,而pipeline越复杂越难以管理
- 新一代graphicAPI比如Vulkan和DX12,开放了硬件算力、内存管理等基础内容,这块做不对游戏会直接crash掉
六,Frame Graph/Render Graph
将管线里的模块分为不同的Frame Graph,类似于unity的SRP,然后利用一个有向无环图去去自动检测所用资源之间的相关性并自动优化
是未来的方向,但目前还不太成熟,大家还在探索。
七,Render to Monitor:V-sync、G-sync
-
Screen Tearing:屏幕更新频率是一定的,但GPU渲染频率会随着场景复杂程度变化,如果不巧刚好显示器刷新时GPU正写到一半,就会出现这种屏幕断裂的情况,这时就需要V-Sync
-
V-Sync:保证每个frame buffer全部写完以后再整个刷新上去,但也会带来刷新率降低、鼠标延迟、画面时快时慢的问题。
QA
- 开放世界的cluster怎么划分:视线锥
- Frame Graph是高层功能还是底层功能:非常底层,绘制基础,可以理解为底层渲染语言,管理资源调用、接口等,feature是在Frame Graph之上的,但目前还在摸索。
- TAA怎么去除鬼影:有很多Hack,比如motion vector太大或颜色差距太大就降低权重(经验值)