Real-Time Renderting 4rd Reading Notes Chap3-8 | RTR4阅读笔记 3-8章
基础的就不细说了,这里主要记一些重要的点

第三章

3.1 并行架构

GPU是高吞吐的,定义为数据处理的最大速率,也是低缓冲的,没有缓存和控制逻辑。采样贴图因为资源不在缓冲,可能很慢,要几百个时钟,这期间gpu会切换到处理另一个fragment,切换是很快的。以此处理了很多fragment,第一个贴图采样终于好了,gpu会回来执行第一个fragment。
这个架构中,通过切换fragment让gpu保持繁忙,把延迟隐藏了。还用了一种SIMD的设计,让多个线程(thread)锁步(lock-step)执行同一命令,好处是能耗和晶体管数量减少了。这多个线程成为一组,NV叫warp,AMD叫wavefronts。每组可能有8-64个线程,每个线程有一个SIMD赛道
比如我们有2000个线程,每个warp32线程,所以总共63个wraps。每个wrap锁步执行,执行到某个指令比如贴图采样需要等待了,就切换到另一个warp执行。每个线程会记录数据在寄存器的,切warp就像换指针没有开销。
实际中warps可能会短暂切出去,用以优化执行。因此一些参数可以衡量这是不是高效,比如越少的线程和warp创建了的话,延迟肯定越高。
最主要的是每个线程寄存器使用量。shader里每个线程需要的寄存器越多,可以存在的线程或者warp就越少。在运行的warps叫占用率(occupancy),高占用意味着有很多warp在等待,静止的处理器就越少。低占用一般意味着低效性能。
另一个是分支结构,if和loop,线程分支,一个warp内,要等所有分支执行完才能继续,要记得是锁步的,所以所有分支顺序执行。

3.8 Pixel Shader

DX11增加了UAV,就是并行可读写的buffer,避免data racing,主要原理是这玩意是atomic的。
DX11.3多了ROV,rasterizer order views, 每个pixel上是有顺序的一串数据,比如透明混合就可以记录每个pixel的颜色,最后按顺序混合。

3.9 合并阶段

DX11和OpenGL4.2有earlyz
DX10有一个双源颜色混合,可以在pixel shader里把两个颜色混合进framebuffer(主要是彩色透明用把)。
ROV保证混合顺序。

3.10 Compute Shader

主要就是cpu-gpu, gpu-cpu有延迟,用cs减少延迟。
可以用来做粒子系统,mesh处理,表情动画,裁剪,图像处理,阴影,DoF等等。

第四章

旋转缩放是线性变换,平移不是,这就要仿射变换,用齐次矩阵。

4.1.3 缩放

镜像矩阵需要把三角面的顶点顺序反向的,要不然面就反了。检查一个变换矩阵是不是有镜像缩放,可以算行列式正负。

4.1.5 变换串联

一般是C=TRS,先缩放,然后旋转,最后平移。

4.1.6 刚体变换

有一个换基公式,比如tangent-space normal会用

4.1.7 法线变换

大家知道应该乘变换矩阵的逆转置,不过算起来可能比较慢。其实旋转式线性变换,转置就是逆,平移又不影响法线,uniform缩放也不影响的。

4.2.2 欧拉旋转的参数

用欧拉角可以反推旋转矩阵(roll, pitch, head)
因此旋转矩阵可以反推欧拉角
要注意的是,如果cosp是0的话,也就是第二个旋转轴是90+180k度,会万向节锁!

4.4 顶点混合

角色骨骼动画里用,很适合GPU计算啊,骨骼矩阵直接VS里计算了,也可以存到texture或者UAV
有时候会有折叠,有一种dual quaternions的方法可以减少。

4.5 变形

就是用权重控制定点混合比例啦。
有一种pose-space deformation的方法,可以混合顶点混合与变形。存一个顶点材质记录置换,tessalation以后置换,避免多余的蒙皮计算。

4.6 几何缓存回放

可能会数据量大,优化就是插值啦等等。

第5章 着色基础

5.1 着色模型

比如例子里的Gooch着色模型
基本思想是比较法线和光照的方向,如果法线朝太阳就用一个暖色,反之用冷色。

5.3.1 评价频率

Vertex Shader-每tess前的顶点
Hull Shader-每patch
Domain-tess后的顶点
Geometry Shader-每面片
Pixel Shader-每像素
插值的时候,向量需要归一化,要不然方向会倾斜。插值完也要归一化
左-归一化的,右-没归一化,注意中间位置方向变了。
朝向某一点的向量插值的时候不能归一化,要不然也会倾斜
一般为了灯光计算,减少灯光的变换,可能要在世界空间计算光照,要不然的话建议在相机空间,精度更高一些。

5.3.2 实例

另一个Gooch变体

5.3.3 材质系统

材质是面向美术的,材质和shader不是一一对应,最常见的是参数化的材质,有材质模板和材质实例。像UE可能会有多个模板衍生出来的模板
参数可以运行时解析,通过uniform的输入决定;也可以编译期做好。
材质系统最重要的是如何划分shader和组合材质。有很多种可能:
根据几何处理不同阶段组合,比如顶点运算,细分,表面着色
根据混合操作,比如discard和透明混合,一般移动端需要单独处理这种shader
根据光照模型的参数和模型本身,这使得光照模型可以重用
根据特性,
根据光照,每个光照计算数值
shader不像cpu程序可以动态链接,编译时就必须是一个整体了。
问题是动态分支还是静态编译?古老的硬件动态分支会比较慢,但是新的硬件处理uniform分支速度挺快的,但问题是寄存器会减少,降低占用率,因此编译器变体还是有价值的。
当代材质系统可能同时有动态分支和静态编译,因为材质数量太多了。比如Destiny里有超过9000个编译的变体。
材质系统的策略可以是:
代码重用,写不同的函数在include里
减法,写ubershader,用编译值和动态分支去掉不用的部分
加法,节点式,比如ue
模板式,接口一致,后面实现可以改变,比如ue的材质领域,unity的surfaceshader

5.4.1 采样理论

采样定律(奈奎斯特极限)采样频率是最大频率的两倍才能保留原有特征
FXAA,超采样,每个像素多2×2
MSAA,不同像素会共享采样
但如果用了HDR,为保证正确就得先tonemapping再解析,很慢
TAA用前帧的结果做抗锯齿

5.5 透明

5.5.1 混合顺序

一般是over操作符了,也就是Blend SrcAlpha OneMinusSrcAlpha,这要从前往后
还有一个under操作符,这个是顺序无关的,不过需要目标也保存一个透明度

5.5.2 顺序无关透明度OIT

可以用under操作符把透明物体单独渲染到一个buffer,再over进不同命物体的buffer。另一种方式是用depth peeling
用两个zbuffer,首先把所有透明不透明的渲染进第一个zbuffer,然后第二个pass渲染透明物体,如果深度一致就渲进第二个color buffer,并把第二近的透明深度写入zbuffer,之后每个pass能得到第n近的透明物体,用under混合进来。
DX11多了UAV可以每个像素存一个链表。
DX11.3多了ROV,可以保存多层透明信息,移动端有一个tile local storage,不过可能比较费
有一种kbuffer的方法,近处的透明物体按几层保存下来,远处的用权重混合
有权重混合OIT的做法,
还有混合以上方法的,比如layered alpha blending method

5.6 显示编码

一般是decode贴图,线性计算,后处理,最后encode进buffer
贴图都是带gamma的主要因为可以直接塞进buffer
gamma错误可能会导致线的渲染出现边缘扭曲(roping)
右边的就是gamma错的

第六章 贴图

6.1.2 连续方程

普通的 循环 镜像 clamp之类
避免周期性可以用wang tile

6.2 贴图

对移动平台来说,dependent texture read是说用pixelshader计算的uv,而不是vertex shader直接计算的uv来读取,老的GPU es2.0之前上会有预抓取,如果用dependent texture read会比较慢
另一种是说贴图读取的结果影响采样的uv,也会比较慢

6.2.5 贴图表示

为了减少状态切换用atlas
ptex方法让每个面有自己的贴图
texturearray也会快一些,比分别绑子材质能快五倍
最新的特性有bindless texture,存一个handle指针,这样就不用每次绑定贴图了

6.2.6 贴图压缩

DXTC/BC基本思路是4×4的块,存两个参考值和一个插值项
问题是颜色在RGB空间,同一个块里没法同时存在
PVRTC用4×4的块,有两个低频信号和插值项
用YCoCg很合适,和RGB就一个矩阵线性变换就好了,而且色度图可以分辨率低一点也可以

6.6 透明贴图

用alphatest可能mipmap的透明度降低,导致远看很稀疏,可以用随机阈值,或者根据覆盖率计算预处理好。

第七章 阴影

7.1.1 平面阴影

相似三角形顶点投射到平面

7.3 阴影体 shadow volume

可以用stencil辅助生成阴影的位置:
  1. 清zbuffer
  2. 渲染
  3. 关zwrite和color,开ztest,渲阴影体,渲到正面就stencil+1
  4. 渲阴影体,渲到背面就stencil-1
最后stencil是0就不在阴影里,不是0就在阴影里。
阴影体用geometry shader生成比较划算,找边缘挤出

7.4 阴影图shadowmap

存一个光线方向的深度图
如果是点光源,可以存六个面的深度图,就像cubemap,叫omnidirectional shadow map
不过深度有误差,所以灯光裁剪平面当然是越近越好。另外也会有走样的问题,比如自阴影,就要引入偏向因子bias factor
太多的bias又造成light leak或peter panning,
有一种方法避免自阴影,只渲染投影体的背面,叫second-depth shadow mapping,第二远阴影图
也可以用最近和次近的中间位置,叫dual shadow map
有时候需要防止像素抖动,就得把阴影图固定到像素上,snap to pixel

7.4.1 分辨率提升

有时候离相机太近的地方阴影图像素比较大,造成了投影走样,可以做投影扭曲
不过问题是光线和视线反向就傻了
另一种是划分frustrem,叫cascaded shadow map,划分距离按指数衰减。为了实时更新划分距离,可以考虑用上一帧的结果做计算,找最近最远距离或者用直方图找最近最远
一些静态的shadowmap不用实时生成,可以用sparse texture采样,和实时的混合
shadowmap渲染也可以有遮挡剔除之类的

7.5 PCF

基本思路就是不仅采样投影点,还采样周围一些点做平均。
不过自阴影可能更严重,因此有几种bias的方法。
主要问题是平均地软阴影,而不是近处硬远处远

7.6 PCSS

按到遮挡体的距离决定采样范围,越远越宽
可以用mipmap采样远处的,叫contact hardening shadows
另一种是用min/max shadow map,存两个mipmap,最大阴影范围和最小阴影范围,这样完全亮和完全暗的就不用扩大采样范围了
PCF计算接收阴影处附近的情况,PCSS计算遮挡处平均距离决定接受阴影处采样半径
存在的问题是,如果有多个阴影遮挡体,估计平均遮挡距离就不太好办了

7.7 Filtered Shadow Map

把深度图存一张,深度的平方存一张
这个是被遮挡的百分比,里面有一个方差项,就是上述两张深度图计算出来的。
这是一个概率项的遮挡百分比!理论依据是切比雪夫不等式。也叫做动量阴影,moment shadow
质量还是不错的,不过多个遮挡体就可能出现漏光light bleeding的问题。有一些方法缓解:
比如convolution shadow map,存傅里叶系数,计算的时候再构造多项式计算
exponential shadow map,存指数系数,一样计算的时候构造,不过指数可能太大了超过float最大
最近有一个moment shadow map,用四个以上动量
总之这是一种不那么费的PCF,采样少一些

7.8 体积投影

可以有第二张阴影图,存透明物体
deep shadow map的技术是说每个像素存一个函数,灯光衰减的函数
opacity shadow map,很多层切片的shadowmap
adaptive volumetric shadow map,每个像素存透明度和层深度,需要UAV和ROV

7.9 不规则Z缓冲阴影

阴影图效率很高,可预测,但是锯齿问题比较多
阴影体积很准,但是代价比较大
另一种解析式的是ray-tracing,之后再谈
还有一种是用光栅化的方法做投影
基本思路是
1 屏幕空间的点投影到灯光空间
2 灯光空间深度图,每个像素存一系列屏幕空间的点
3 对遮挡体进行保守光栅化
4 屏幕空间对那些点测试,在不在灯光空间光栅化的三角形中,如果在就说明在阴影里
这种方法避免了bias,全境封锁用了IZB和PCSS的结合

7.10 其他应用

有一种屏幕空间阴影
把深度图当成高度场,用raymarching到灯光看是否与这个高度场相交,质量比较高

第八章 灯与颜色

辐照度 irradiance,单位面积上功率,这个是物体表面接受的光强
辐射亮度 radiance,单位面积单位立体角的功率,这个是人眼感知的,不受距离影响,物体表面辐射亮度无论距离

8.1.3 比色法

人眼有三种色彩细胞,每种相应特定的波长(所以是RGB三个通道)
测试方法是看人眼感觉,哪三种特定波长正好可以组合出所有颜色,测试的结果就是RGB,三种波长混合比例叫color-matching function

8.1.4 用RGB渲染

RGB是感知的量,而不是实际的量。比如物体的反射,其实是遵从反射曲线的,不同波长有不同反射率,但RGB就简化成三个了。有可能有误差啊,一个全波段的光仅反射RGB,就没啥了,但是如果给一个反射曲线能反射不少东西
上 反射曲线 中 RGB反射率 下 入射光线
所以说如果用RGB做预测,就谬之千里了,目标仅仅是产生看上去合理的结果plausible,not predictive simulation

8.2.1 HDR

高明度可能到10000cd/m2,一般屏幕也就100cd/m2,实际上商用显示器最高也能到1500cd/m2,

8.2.2  Tonemapping

是从场景辐亮度转换到屏幕辐亮度。
有很多误解,其实它目的不是屏幕到屏幕的转换,也不是为了让HDR到LDR,尽管这很重要。最好是认为它是影像重建,让显示的影像尽可能接近原有场景的感知印象。
perceptural likeness of the original scenes, as did Renaissance painters.
frostebite呢,在SDR上会用比较激进的曲线,在HDR10设备上不那么激进,在Dolby设备上就不用tonemapping了

发表评论

邮箱地址不会被公开。 必填项已用*标注