unity-shader-GPU三部曲阅读笔记
unity-shader-GPU三部曲阅读笔记
前篇
浅墨的游戏编程 - https://zhuanlan.zhihu.com/game-programming
github 版本 -
里面很多图形书籍的总结, 非常不错. 如: GPU精粹三部曲
- Addison-Wesley出版社的《GPU GEM I~III》
- CRC Press出版社的《GPU PRO 1~7》
- Black Cat Publishing出版社的《GPU Zen》
- [【GPU精粹与Shader编程】《GPU Gems 1》全书核心内容提炼总结](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 1》全书提炼总结)
GPU GEM 1
次表面散射 SSS
参考链接: [四、次表面散射的实时近似 (Real-Time Approximations to Subsurface Scattering)](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 1》全书提炼总结#四次表面散射的实时近似real-time-approximations-to-subsurface-scattering)
说明
次表面散射(Subsurface Scattering),简称SSS,或3S,是光射入非金属材质后在内部发生散射,最后射出物体并进入视野中产生的现象,即光从表面进入物体经过内部散射,然后又通过物体表面的其他顶点出射的光线传递过程。
参考仓库
Custom Phase Screen-Space Subsurface Scattering - https://github.com/CustomPhase/CP_SSSSS
Unity_SimpleSSS - https://github.com/haxflying/Unity_SimpleSSS
阴影贴图抗锯齿(Shadow Map Antialiasing)
参考链接: [十四、阴影贴图抗锯齿(Shadow Map Antialiasing)](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 1》全书提炼总结#十四阴影贴图抗锯齿shadow-map-antialiasing)
图 (a)每像素取1个样本 (b)每像素取4个样本 (c)每像素取16个样本
可以看到3幅图中的显示效果区别很明显,图(c)中每像素取16个样本,效果最为出色,达到了反走样的预期。
unity 中的 soft shadows, 软阴影(Soft shadows),在上下文中叫抗锯齿阴影(antialiased shadows)其实更合适
GPU GEM 2
一、实现照片级真实感的虚拟植物(Toward Photorealism in Virtual Botany)
参考链接: [ 1.2.1 通过溶解模拟Alpha透明(Simulating Alpha Transparency via Dissolve)](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 2》全书提炼总结/Part1#121-通过溶解模拟alpha透明simulating-alpha-transparency-via-dissolve)
在渲染草的时候,想要使用透明来改善视觉混合和在接近虚拟栅格边界时的淡出。然而,基于Alpha的透明并不理想,因为它需要排序且速度很慢。虽然可以利用草较为杂乱的性质最小化一些排序技术,但实际上可以完全忽略这种做法。
为此,采取溶解效应(dissolve effect),也称纱门效应(screen-door effect)的方法,代替Alpha混合来模拟透明。首先,用一个噪音纹理调制草纹理的Alpha通道,然后使用Alpha测试从渲染中去除像素,通过从0到1调节Alpha测试数值,纹理表现出溶解的现象。这一过程如下图所示。
图 草纹理的构成
(a)漫反射纹理; (b)美工创建的alpha通道; (c)Perlin噪音纹理; (d)Perlin噪音与Alpha相乘的结果。这可以在像素着色器,或固定的Alpha测试值产生淡出。
这项技术的有点是Alpha测试的速度快而且与顺序无关。我们不再需要排序,草依然可以在远处淡出。虽然溶解在正常的情况下看起来不像真实的Alpha透明那么好,但可以利用自然的分形属性来完全掩饰任何溶解技术的视觉失真。
顶点色 表现 颜色多样性
【注:每颗草的顶点中都包含RGB的信息。在此场景中,颜色值来自Perlin噪声函数,模拟了比较绿的草,并修补了不太健康的褐色】
1.2.4 风
当风吹过,草地泛起涟漪,草变得鲜活起来了。
通过每一帧偏移草方形顶部的两个顶点,可以使方形在风中摇摆。可以使用一个正弦近似的和计算这个偏移,类似计算水表面的波动[Finch 2004]。这个技巧是在顶点定义中带一个混合权重,草方形的顶部两个顶点被设为1,底部两个顶点为0,然后把这一数值乘以风的缩放系数,底部的顶点仍然牢牢地依附在地上。
对于另外的变化,可以在种植期间略微随机变换顶部的两个顶点权重。这模拟了草的软硬区别。
1.7 业界领先的植物渲染解决方案 SpeedTree
也需要提到的是,SpeedTree是很优秀的树与灌木层的中间件,是植物渲染方面业界领先的解决方案。自2008年以来的各种一线3A游戏,如《蝙蝠侠》、《使命召唤》、《神秘海域》系列,包括近期的《彩虹六号》、《孤岛惊魂5》、《地平线:黎明》、《絶地求生》、《最终幻想15》等游戏,都使用了SpeedTree作为树木植物相关渲染的解决方案。
电影方面,包括最近的《复仇者联盟3》、《黑豹》在内的好莱坞大片,以及早一些的《速度与激情8》《魔兽》《星球大战:原力觉醒》等大片,也都使用了SpeedTree作为树木植物相关渲染的解决方案。
SpeedTree官网:https://store.speedtree.com/
二、GPU通用计算:流式编程与存储体系(General-Purpose Computation on GPU)
四、几何体实例化的内幕(Inside Geometry Instancing)
参考: [几何体实例化的内幕(Inside Geometry Instancing)](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 2》全书提炼总结/Part1#四几何体实例化的内幕inside-geometry-instancing)
使用几何体实例(Geometry Instancing)的优势在于可以对渲染性能进行优化(最小化花费在提交渲染批次上的CPU时间)。
想要使用应用程序最小化状态和纹理变化次数,并在一次Direct3D调用中把统一批次中的同一个三角形渲染多次。这样就能最小化花费在提交批次上的CPU时间。
这章描述了4种不同的技术来实现 Geometry Batch:
- 静态批次(Static batching)。最快的实例化几何体的方法。每个实例一旦转换到世界空间,则应用它的属性,然后每一帧把已经转换的数据发送给GPU。虽然简单,但静态批次是最不具灵活性的技术。
- 动态批次(Dynamic batching)。最慢的实例化几何体的方法。每个实例在每帧都流向GPU存储器,已经转换并应用了属性。动态批次无缝地支持蒙皮并提供了最灵活的实现。
- 顶点常量实例(Vertex constants instancing)。每个实例的几何体有多份副本一次复制到GPU存储器中的混合实现。然后实例属性在每一帧通过顶点常量设置,而由于顶点着色器完成几何体的实例化。
- 通过几何体实例化API的批次(Batching with Geometry Instancing API)。使用DirectX等图形API提供并支持的几何体实例化,此实现提供了灵活快速的几何体实例化解决方案。与其他方法不同的是,这不需要在Direct3D顶点流中复制几何体包
高效地渲染相同的几何体(静态批次、动态批次、顶点常量实例化,通过几何体实例化API的批次),他们各有优劣,根据应用和渲染的物体类型分别选取。一些建议:
- 有相同几何体的许多静态实例的室内场景,很少或从不移动的实例(比如墙壁或家具),采用静态批次较为理想。
- 有许多动画物体实例的一个室外景物,如策略游戏中有上百个士兵的大战场,在这种情况下,动态批次或许是最好的解决方案。
- 有许多植被和树以及许多粒子系统的室外场景,其中有很多经常需要修改的属性(例如,树和草随风摇摆),几何体实例API可能是最好的解决方案。
五、分段缓冲(Segment Buffering)
分段缓冲(segment buffering)技术汇集了在场景中彼此靠近的多个实例,把它们合并到“超级实例(über-instances)”中,这样减少了批次的数目,而且提供了解决批次瓶颈问题的一个简单优化的方案。
分段缓冲(segment buffering)技术自动合并相似的实例,同时保持呈现单独实例的大部分优势。分段缓冲的主要好处在于非重复的外观,以及无需重新绘制原始的实例,就像这部分实例从可见集合中被删除了一样,所以可以明显减少一个显示帧中渲染的批次的数目。而其具体步骤分为三步,原书中有进一步地说明。
而关于分段缓冲(Segment Buffering)的改进,文章提出了结合自动纹理图集生成(automatic texture-atlas generation [NVIDIA 2004])的相关思路。
一、将顶点纹理位移用于水的真实感渲染(Using Vertex Texture Displacement for Realistic Water Rendering)
1.4 实现细节概述
参考: [1.4 实现细节概述](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 2》全书提炼总结/Part2#14-实现细节概述)
可以把所有需要实现的计算分为两部分:
- 几何位移计算 (置换贴图增加曲面细节)
- 光照计算 (法线贴图增加视觉效果)
因为水面细分得很精细,所以可以只在片段程序级实现光照计算,而把位移映射的工作移交给顶点级,以减轻片段的负担。需要注意,如果在顶点级实现光照计算可能产生明显的走样,尤其是远处的物体。
1.6 提高渲染质量与优化性能的一些方案
参考: [1.6 提高渲染质量与优化性能的一些方案](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 2》全书提炼总结/Part2#16-提高渲染质量与优化性能的一些方案)
1.6.1 为双线性过滤打包高度值
访问顶点纹理的代价十分昂贵,在旧的GeForce 6系列的硬件上,一个顶点纹理的访问会在顶点程序中产生明显的延迟。所以比较合适的策略是把顶点程序中访问纹理的次数降到最低。另一方面,过滤纹理值非常必要,否则图像质量就会显著降低。
为了减小插值时纹理访问的次数,可以用一种特别的方法创建纹理,这样使每个纹理包含了一次双线性纹理查找必需的所有数据。因为高度图本质上是单通道的纹理,可以把 四个高度值打包到一张四通道纹理的一个纹素内,以实现优化。
1.6.2 使用分支避免不需要的工作
即使使用了优化的纹理过滤,渲染水体时,访问纹理的次数仍然很高,这会严重影响性能。一种方法是减少渲染的顶点数,但是这将全面地降低视觉上的细节并且增加失真度。
需要渲染的水体含有大量的几何数据,但其中有些三角面完全在屏幕之外。对这样的三角形,顶点程序仍然要进行处理,这其实是一种浪费。如果能跳过在相机视野之外三角形的相关计算,就可以在每个顶点上节约大量的工作。
以下的伪代码表达了这个方法的实现:
1 | float4 ClipPos = mul(ModelViewProj, INP); |
在上面的代码中,使用了裁剪空间的顶点位置来确定当前的顶点是否位于视野之中,然后只对需要的顶点进行复杂运算即可。
GPU GEM 3
三、通用的折射模拟(Generic Refraction)
五、常规基于模糊的次表面散射方法
参考:
5.1 纹理空间模糊(Texture Space Blur)
5.2 屏幕空间模糊(Screen Space Blur)[2009]
第2章 群体动画渲染(Animated Crowd Rendering)
使用实例化(instancing)方法,可以通过减少Draw Call、状态更改以及缓冲区更新的数量来减少CPU的开销。
这章中展示了如何使用顶点纹理存取的DirectX 10实例化来实现基于硬件调色板的蒙皮角色(skinned characters)。这个demo同时使用了常量缓冲区和系统变量SV_InstanceID来有效实现这项技术。在Intel Core 2 Duo GeForce 8800 GTX显卡上,能够实现大约1万个人物拥有不同的动画和蒙皮。
蒙皮实例化(Skinned instancing)这项技术适用于实时地渲染数量庞大且彼此独立的动画人物。它使用顶点纹理存取来读取存储在单一纹理中的动画数据,也使用了SV_InstanceID来索引包含了示例数据的常量缓冲区(位置和动画时间)。而配合一个简单易行的LOD系统,能在合适距离上有更高的多边形/光照细节。
图 Instancing Basics
图 LOD数据的布局
本章英文原书全文传送门:
https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch02.html
第8章 区域求和的差值阴影贴图(Summed-Area Variance Shadow Maps)
参考: [区域求和的差值阴影贴图](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 3》全书提炼总结/Part2#第8章-区域求和的差值阴影贴图summed-area-variance-shadow-maps)
这章主要讨论了阴影贴图过滤和柔和阴影,回顾了差值阴影贴图算法,并解释了如何用它来解决很多常见的阴影贴图问题(如缩变锯齿、偏移及软阴影)。同时还介绍了一种简单且有效的技术,该技术能够显著减少差值阴影贴图(Variance Shadow Maps,VSM)中的light-bleeding失真。最后,文章介绍了一种基于差值阴影贴图(Variance Shadow Maps,VSM)和区域求和表(Summed-Area Tables,SAT)的实时阴影算法。
对任意的方波过滤器区域,该算法都能有效地计算出阴影权值,最终文章得出结论,区域求和的差值阴影贴图(Summed-Area Variance Shadow Mapping ,SAVSM)是计算没有锯齿现象的柔和阴影的理想算法。
图8-10样本数据和相关的区域求和表
图 区域求和的基于差值阴影贴图(Summed-Area Variance Shadow Mapping ,SAVSM)算法渲染的硬边和软边阴影
第13章 后处理特效:体积光散射(Volumetric Light Scattering as a Post-Process)
参考: [后处理特效:体积光散射](https://github.com/QianMo/Game-Programmer-Study-Notes/tree/master/Content/《GPU Gems 3》全书提炼总结/Part2#第13章-后处理特效体积光散射volumetric-light-scattering-as-a-post-process)
GPU PRO 1
一、《孢子(Spore)》中的风格化渲染 | Stylized Rendering in Spore
参考: [《孢子(Spore)》中的风格化渲染 | Stylized Rendering in Spore]([https://github.com/QianMo/Game-Programmer-Study-Notes/blob/master/Content/%E3%80%8AGPU%20Pro%201%E3%80%8B%E5%85%A8%E4%B9%A6%E6%8F%90%E7%82%BC%E6%80%BB%E7%BB%93/README.md#%E4%B8%80%E5%AD%A2%E5%AD%90spore%E4%B8%AD%E7%9A%84%E9%A3%8E%E6%A0%BC%E5%8C%96%E6%B8%B2%E6%9F%93--stylized-rendering-in-spore](https://github.com/QianMo/Game-Programmer-Study-Notes/blob/master/Content/《GPU Pro 1》全书提炼总结/README.md#一孢子spore中的风格化渲染–stylized-rendering-in-spore))
下图显示了《孢子》中细胞阶段的过滤器链如何使用由渲染管线的其他阶段生成的多个输入纹理,并形成最终的合成帧。