深入理解渲染流水线----学习Shader的基础(入门必备)
序:今天早晨偶然看到一个名词Unity-SRP,SRP吓我一跳。。。一时间没反应过来是什么东西,好高大尚的名词,遂决定写这篇文章。一来想把接触过的都总结下来,所谓的前人栽树后人乘凉(把自己说的高尚了点。。。hhh)与君共勉;二来,一直对shader比较感兴趣,作shader系列的博客深挖一些技术知识。
题外知识:SRP,其实就是Scriptable Render Pipeline,可编程脚本渲染管线。别被这么高端的名词吓到,很简单,它就Unity中通过C#可以对渲染进行配置和执行的一种方式(Unity2018下载自带,对于开发者来说更加方便。新版Unity的SRP这块我再后面会详细介绍,现在先简单有个概念)。渲染管线:看起来应该是个名词,指的是将一个对象显示到屏幕上这个过程,这个流水线,我们要研究的就是这个过程中的一些技术。
正题:渲染管线即渲染流水线,这个流水线任务是从三维的物体生成一张二维的图像,而流水线的工人是CPU和GPU。这个流水线一共分为三个阶段:
应用阶段-->几何阶段-->光栅化阶段
应用阶段:
负责人:开发人员主导;
执行者:CPU;
工作:1.准备好场景数据,包括摄像机,模型,光源等 ;2.不可见的做一些剔除;3.设置模型的渲染状态(eg:材质、纹理、shader等) 等。
输出:渲染图元(通俗点应该就是点,线,面等)
分为三个阶段:
1.数据加载到显存:所有渲染所需的数据先从硬盘加载到内存然后又被加载到显存(因为显卡对显存的访问速度快)
2.设置渲染状态(即告诉GPU该如何渲染),根据不同的渲染状态,网格会渲染成不同结果。
3.调用DrawCall(即DC)。发起方CPU,接收方GPU。CPU告诉GPU可以开始渲染了,GPU就开始根据之前的渲染状态和提前准备好的数据计算,输出屏幕上的像素。
几何阶段:
执行者:GPU;
工作:逐顶点、逐多边形的看看需要绘制什么,怎么样绘制和绘制在哪里。
输出:屏幕空间的二维顶点坐标,也包含每个顶点的深度和着色等信息。
光栅化阶段:
执行者:GPU;
工作:用上个阶段的数据产生像素,渲染到屏幕上。
后两个阶段就是GPU的流水线所做的事情,下面我们具体看看GPU的流水线(将上面后两个阶段更加细分):
几何阶段:顶点数据-->顶点着色器-->曲面细分着色器-->几何着色器-->裁剪-->屏幕映射
光栅化阶段: -->三角形设置-->三角形遍历-->片元着色器-->逐片元操作-->屏幕图像
下面具体介绍一下流水线中的这几个阶段:
顶点着色器:完全可编程,实现顶点空间变换、顶点着色等。
这些顶点相互独立,并行处理,主要完成坐标变换(注:可以改变顶点的位置,所以可以模拟水面变化等)和逐顶点光照。坐标变化:顶点坐标从模型空间到齐次裁剪空间。我们常看到的这一句shader代码就完成了这个基本操作:o.pos = mul(UNITY_MVP, v.position);(最终得到的是归一化的设备坐标,即NDC,DirectX中这个坐标的z分量是0~1,OpenGL,Unity使用的这个坐标的z分量是 -1 ~1)
曲面细分着色器:可选,细分图元;
几何着色器:可选,逐片元着色或产生更多片元;
裁剪:可配置,将不在摄像机视野中的顶点裁掉,剔除一些三角面片。完全不在视野中的裁剪掉,一部分在视野里的裁掉后用新顶点(交界处)代替。
屏幕映射:不可配置和编程,把图元坐标转换到屏幕坐标系中。这步输入仍是三维的坐标,将图元的x,y转换到屏幕坐标系下(二维,和分辨率有关)。opengl左下角为(0,0),DirectX左上角为 (0,0)。
三角形设置,三角形遍历:固定函数阶段。之前的输出都是顶点和顶点信息,现在开始计算三角网格的边,三角形设置开始计算光栅化一个三角形网格所需的信息。三角遍历会检查每个像素是否被一个三角网格覆盖,如果覆盖就生成一个片元,使用三个顶点的信息对覆盖区域的像素进行插值,输出一堆片元。片元还不是最终的像素,里面还有一些状态,用来生成最终像素的颜色。
片元着色器(DX中也叫像素着色器):输入是上个阶段的顶点插值后的信息,输出是颜色值。可编程,逐片元着色。很多渲染技术在这里。
逐片元操作:不可编程,可配置。eg:修改颜色、深度缓冲、混合等。决定每个片元的可见性;如果通过了测试,将这个片元的颜色值和已经存储在颜色缓冲区的颜色合并(混合)。如下图:
片元-->模板测试-->深度测试-->混合-->颜色缓冲区
总结:ok,就这么多了,如果能理解了这些,我想基本上对渲染管线有个基础的了解,才可以进而去学习更高级的图形渲染技术。欢迎大家来拍砖!
参考 《Unity Shader 入门精要》冯乐乐
阅读更多
- Unity Shader入门精要学习笔记 - 第2章 渲染流水线
- Java基础学习总结(71)——深入理解Java虚拟机内存
- 深入学习Django源码基础1 - 深刻理解Python中的元类(metaclass)
- Android入门:深入学习理解 Handler HandlerThread AsyncQueryHandler 三者的关系
- Java基础学习总结(71)——深入理解Java虚拟机内存
- 基础入门_Python-进程相关.深入理解子进程/守护进程/进程高可用实现?
- [置顶] Unity Shader入门精要学习笔记 - 第2章 渲染流水线
- Unity Shader入门精要学习笔记 - 第16章 Unity中的渲染优化技术
- Unity Shader入门精要学习笔记 - 第4章 学习 Shader 所需的数学基础
- Shader 入门笔记(二) CPU和GPU之间的通信,渲染流水线
- Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照
- UnityShader入门精要学习笔记(九):基础纹理之渐变纹理与遮罩纹理
- Unity Shader入门精要笔记(一):渲染流水线
- Unity Shader入门精要学习笔记 - 第4章 学习 Shader 所需的数学基础
- Android入门:深入学习理解 Handler HandlerThread AsyncQueryHandler 三者的关系 收藏
- linux学习入门 基础部分(5)[用户理解 用户涉及到的系统配置文件 用户管理《建立,删除,查看,更改》 权力下放 忘记密码。
- Android入门:深入学习理解 Handler HandlerThread AsyncQueryHandler 三者的关系
- Android入门:深入学习理解 Handler HandlerThread AsyncQueryHandler 三者的关系 收藏
- Unity Shader入门精要学习笔记 - 第4章 学习 Shader 所需的数学基础
- Shader入门理论(三)渲染流水线总结解惑