找回密码
 立即注册
查看: 382|回复: 0

《Unity Shader入门精要》学习笔记(一)

[复制链接]
发表于 2022-9-3 16:17 | 显示全部楼层 |阅读模式
前言:
笔者第一次写 知乎文章,难免有不足之处,还请见谅。
在学习《Unity Shader入门精要》(以下简称入门精要)前,笔者听完了GAMES101和202,(但作业没写,回头补www),所以有了一点点理论基础来看的入门精要,借用闫老师的观点,还是建议先对图形学有个基本的认识再上手shader以及图形API之类的书籍。笔者当时学101和202的时候写的是纸质笔记,于是就立了flag,入门精要要写一写电子笔记。落笔时笔者已读完全书,当时留下了很多疑问打算在写笔记的时候去解决。(话说看完全书又要从头看起的感觉真的不好诶,已经不想再往下写了...)因为类似的文章已有不少, 大概率我这篇看得人少,所以本系列以我个人的问题和解决为主,个人笔记嘛,废话和莫名其妙的问题是会比较多的啦 >-:< 希望能对你有所帮助
本系列文章仅为个人学习笔记,学识尚浅,有错误之处欢迎指出。此外,乐乐女神的原书写的真的非常好,强烈建议阅读原书,本文也是基于原书之上做的一些笔记和一些扩展。

本篇文章对于入门精要第一章和第二章(但实际上只有第二章...)

正文:
第一章:
无笔记
第二章:
渲染流水线(渲染管线 Render Pipeline)的最终目的在于生成或者渲染一张二维纹理。渲染流水线的工作任务在于由一个三维场景出发,生成(或渲染)一张二维图像。
这里与“三渲二”区分一下,三渲二意在模仿2D手绘般的感觉,也就是卡通渲染(Cel shading),算是非真实感渲染(NPR)的一种,而我们这里说的三维场景渲染到二维图像则是不管它是非真实感的还是真实感的。

渲染管线三个阶段:应用阶段-几何阶段-光栅化阶段




一,应用阶段(Application Stage)(由开发者决定的,即我们不能进行操作):
1,准备好场景数据 (把数据加载到显存中)
2,剔除不可见的物体(粗粒度剔除)(culling)
3,设置渲染状态
(注:渲染管线内部维护着一些状态值。在我们调用渲染API函数进行绘制之前我们需要设置这些状态值。
这些状态值指导GPU如何渲染我们传递到显存的模型和纹理数据。我们称这些状态值为“渲染状态(Render States) ”。渲染状态包括Shader、Texture、Material、Light内部定义的各种状态等)
4,调用drawcall(CPU->GPU,该命令仅指向有一个需要被渲染的图元的列表)

这一阶段输出渲染图元(可以是点,线,三角形等)
二,几何阶段(Geometry Stage):需要绘制的图元是什么,怎样绘制它们,在哪里绘制它们
(顶点着色器,曲面细分着色器,几何着色器,裁剪,屏幕映射 都在这个阶段)

顶点着色器(Vertex Shader):输入来自CPU,主要(必须)完成坐标变换(模型空间->齐次裁剪空间)。之后硬件会做透视除法得到归一化的设备坐标(NDC)

有时(必要时)顶点着色器会使用逐顶点光照(高洛德着色 (Gouraud shading)),也就是先算出顶点的颜色,然后通过在渲染图元内部线性插值,当光照模型中有非线性的计算时(如计算高光反射),这种逐顶点的光照就会出问题。另外由于是图元内部线性插值,会导致渲染图元内部的颜色总是暗于顶点处,在某些情况下会产生明显的棱角现象。而Phong着色则没有先去算出顶点颜色,而是先对法线进行插值,在片元着色器中去算每个像素的颜色
(这块关于着色频率的内容,在GAMES101中的第八课有提到)



作为高洛德着色(Gouraud shading),右为Phong着色(Phong shading)

曲面细分着色器(Tessellation Shader)(可选):对三角面进行细分,依次来让模型更精细,可以借助曲面细分着色器实现LOD,远处模型粗糙,近处模型精细


几何着色器(Geometry Shader)(可选):几何着色器则以完整的图元(Primitive)作为输入数据。例如,以三角形的三个顶点作为输入,然后输出对应的图元。与顶点着色器不能销毁或创建顶点不同,几何着色器的主要亮点就是可以创建或销毁几何图元,需要注意的是,几何着色器的输出图元不一定和输入图元相同。几何着色器的一个拿手好戏就是将一个点扩展为一个四边形(即两个三角形)。


裁剪(Clipping)(不可编程但可配置):部分在视野外部分在视野内的图元进行一个裁剪


实际上可配置的东西不多,举个配置例子:
在管线后面的Z-Test阶段通过逐片元的z值比较去做,也就是把z大于1的片元剔除。这个剔除在OpenGL里是可配置的,你可以把它关掉让你的渲染结果内包含远平面之外的东西。

裁剪中的保护带裁剪(一种优化)(Guard-band clipping):
我们可以不裁剪,光栅化过程中会扫描屏幕中的区域并询问该像素的覆盖情况,只要三角形覆盖测试不出错屏幕外的像素肯定不会被光栅化到。但三角形覆盖测试在一个固定精度的整数运算中完成,而我们的整数精度是有上限的,如果三角形的一个顶点在视口很远的地方那么可能产生整数溢出,导致不在三角形内的像素被光栅化到三角形内产生错误结果。

为了避免产生错误结果,我们还是要做一些裁剪(保护带裁剪),把超出视口又不会产生整数精度溢出的部分称作保护带。



图中心很小的蓝框白底正方形是我们的视口,粉红色的大方框是我们的保护带

完全在我们所需要的视口外(绿色,蓝色):直接剔除
同时占据视口和保护带(黄色):完全保留,留给三角形覆盖测试
同时占据视口,保护带,保护带之外的区域(紫色):做裁剪
由于紫色的这种三角形还是很少的,所以能节省大量裁剪操作

屏幕映射(Screen Mapping)(GPU固定实现,我们无法进行任何操作)
裁剪后,把NDC的xy(-1-1)到(1,1)转换到屏幕坐标系中(与显示画面的分辨率有很大关系)


注意这边DirectX(检查DX)和OpenGL存在坐标系差异,我们再之后会有判断平台并矫正差异的操作(实际上Unity已经帮我们做了这个矫正了,只是在部分情况下Unity不会做矫正而需要我们自己去做)

三,光栅化阶段
对上一阶段得到的逐顶点数据进行插值,然后再进行逐像素处理
(三角形设置,三角形遍历,片元着色器,逐片元操作 都在这个阶段)

三角形设置(Triangle Setup)(GPU固定实现,我们无法进行任何操作)
简单理解:把三角形的三个顶点坐标和三条边的方程传给三角形遍历阶段
复杂点,参考这篇文章(我菜看不懂)
三角形遍历/扫描变换 (Triangle Traversal/Scan Conversion)(GPU固定实现,我们无法进行任何操作):
判断一个三角网格覆盖了哪些像素,并用三个顶点的信息对整片覆盖区域进行插值。


先把屏幕用8*8像素大小的大块区分开,对三角形的包围盒进行扫描,某一大块如果没有与三角形的包围盒相交,那就可以直接忽略了。对有相交的大块,我们再遍历所有像素去判断它是否在三角形内。

片元着色器(Fragment Shader)(可编程)
输入:上个阶段对顶点信息插值得到的结果
输出:一个或多个颜色值

纹理采样在这一阶段完成,但纹理采样需要整个三角形覆盖的片元的纹理坐标,我们会先在顶点着色器阶段输入三角形每个顶点对应的纹理坐标,然后经过插值就能得到我们要的片元纹理坐标了。(该操作会在后面频繁出现)



在顶点着色器里的代码



在片元着色器中的代码

逐片元操作(Per-Fragment Operations)(可配置但不可编程)
1,决定片元的可见性(模板测试,深度测试)
2,通过测试之后,把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行合并(对于不透明物体直接覆盖,对于透明物体则采用混合)

模板测试:限制渲染的区域


深度测试:先设置场景为无限远,深度无限大。不断更新,如果比深度缓冲里的值小,那就更新保留,如果大,那就去掉


笔者自己画了个简易的示意图,如图8比无穷小,保留并更新深度缓冲,9比8大则不会更新深度缓冲,并且将其舍弃
如果不开深度写入,则只测试,不更新。(GAMES101第七课有提及)

Early-Z:将深度测试提前(但如果进行透明度测试,则导致深度测试无法提前)

逐片元操作输出到屏幕图像之后,渲染流水线的工作就结束

CPU与GPU之间数据加载
数据是从 硬盘->内存->显存 的



CPU与GPU之间并行工作
CPU和GPU之间有个命令缓冲区,CPU往里面加命令,GPU从里面读命令。


Draw Call
Draw Call是命令缓冲区中的一种命令。在每次调用Draw Call之前,CPU需要做很多工作。Draw Call过多的话CPU就会把大量的时间花在提交命令上,容易造成CPU过载导致帧率下降。

批处理
把很多小的Draw Call合并成一个大Draw Call,但适合于静态的物体,而且必须是同一钟渲染状态(不能使用不同的材质)

参考文献:
  《Unity Shader入门精要》

封面图出自:高牛奶_Milkko

下篇:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 14:03 , Processed in 0.089734 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表