UnityShader入门精要阅读笔记

时间:2021-01-18 10:19:33

一些名词解释:

图元(primitive):图元就是组成图像的基本单元,比如三维模型中的点、线、面等等,注意图元(entity)与片元(primitive)的区别,片元就是以后的像素点,它比像素多一些位置、法向量等属性。

网格(Mesh):一般来说,3D世界里的面都是由网格(三角网格)组成的。模型上的小网格就是一个Mesh,这些网格各*不同的三维顶点(Vector3),共同组成了一个3D模型。

片元(fragment):片元是光栅化阶段的三角形遍历后产生的,被三角网格覆盖的每个像素点都会产生片元,片元是一个状态的集合,用于计算每个像素的最终颜色,这些状态包括但不限于这个点的屏幕坐标,深度信息,以及其他从几何阶段输出的顶点信息,例如法线,纹理坐标等。  

面片():

 

 

2.1章主要内容:

渲染流程可以分为三个阶段:

1、应用阶段(Application Stage)  

  由应用主导,通常由CPU负责实现,开发者拥有绝对控制权。最重要的工作是输出渲染图元

  基本上包括下列操作:

          1、准备场景数据,包括场景的摄像头、模型、等等。

          2、优化渲染性能,包括将不需要被渲染的物件(类似不可见的东西)剔除出去,这样就不需要增加不必要的渲染工作量。

          3、设置好渲染状态,包括但不限于材质、纹理、使用的shader等等。

2、几何阶段(Geometry Stage)  

  用于处理所有和我们要绘制的几何相关的事情。例如要绘制什么,怎么绘制,在哪里绘制,这一阶段在GPU进行。

  这个阶段比较重要的任务就是把顶点坐标变换到屏幕空间中,再交给光栅器进行处理。

3、光栅化阶段(Rasterizer Stage)  

  这一阶段会使用上个阶段传递来的数据去产生屏幕上的像素,并渲染出最后的图像,这一阶段也是在GPU上进行。光栅化的主要任务是决定每个渲染图元中的哪些像素应该被绘制在屏幕上。它需要对上一个阶段得到的逐顶点数据(例如纹理坐标、顶点颜色等)进行插值,然后再进行逐像素处理。

 

下图是书上截图下来的内容

UnityShader入门精要阅读笔记

 

2.2 CPU和GPU之间的通信

应用阶段大概可以分为以下三个阶段:

1、把数据加载到显存中。(硬盘->RAM->VRAM Video Random Access Memory)

UnityShader入门精要阅读笔记

 

2、设置渲染状态。

  这些状态定义了场景中的网格是怎么样被渲染的。例如:使用哪个顶点着色器(Vertex Shader)/片远着色器(Fragment Shader)、光源属性、材质等。

  下图显示了当使用同一种渲染状态时,渲染三个不同网格当效果。 

UnityShader入门精要阅读笔记

 

3、调用Draw Call。

  Draw Call其实就是一个命令,发起方是CPU,接收方是GPU。这个命令仅仅会指向一个需要被渲染的图元(primitives)列表,而不会再包含任何材质信息,如下图所表示。

UnityShader入门精要阅读笔记

 

 

2.3 GPU流水线

  当GPU从CPU那里得到渲染命令后,就会进行一系列流水线操作,最终把图元渲染到屏幕上。

  几何阶段和光栅化阶段可以再细分为如下的若干个流水线阶段。

 

UnityShader入门精要阅读笔记

   GPU的渲染流水线实现。颜色表示了不同阶段的可配置性或可编程性:绿色表示该流水线阶段是完全可编程控制的,黄色表示该流水线阶段可以配置但不是可编程的,蓝色表示该流水线阶段是由GPU固定实现的,开发者没有任何控制权。实线表示该shader必须由开发者编程实现,虚线表示该Shader是可选的

    几何阶段接受来自CPU处理后的顶点数据作为输入,这些数据是由应用阶段加载到显存中,再由Draw Call指定的,这些数据随后被传递给顶点着色器。

 

  顶点着色器(Vertex Shader)是完全可编程的。通常用于实现顶点的空间变换、顶点着色等功能。

  曲面细分着色器(Tessellation Shader)是可选着色器。用于细分图元。

    几何着色器(Geometry Shader)同样是一个可选等着色器,可以被用于执行逐图元(Per-Primitive)的着色操作。

  

  接下来是裁剪(Clipping),这一阶段将不在摄像机视野内的顶点裁剪掉,并剔除某些三角图元的面片。

  屏幕映射(Screen Mapping)是几何阶段的最后一个阶段。这个阶段不可配置和操作的,它负责把每个图元的坐标转换到屏幕坐标系中。

 

  三角形设置(Triangle Setup)和三角形遍历(Triangle Traversal)阶段是光栅化概念阶段中的固定函数阶段。 

  片元着色器(Fragment Shader)则是完全可以编程的。它用于实现逐片元(Per-Fragment)的着色操作。

 

  逐片元操作(Per-Fragment Operations)阶段负责执行很多重要的操作,例如修改颜色、深度缓冲、进行混合等,它不是可编程的,但具有很高的可配置性

 

接下来对一些主要对流水线阶段做详细解释:

  顶点着色器:  1、流水线的第一个阶段,输入来自CPU;

            2、处理单位是顶点,输入进来的每个顶点都会调用一次着色器;(这也可以侧面说明,为什么要减少模型或者是图片的顶点数量)

            3、顶点着色器本身不可以创建或者销毁任何顶点,且无法得到顶点与顶点之间的关系(例如我们无法知道两个顶点是否属于同一个三角网格);

            4、因为顶点相互独立的特性,使得这一阶段的处理速度是快速的。

            

            完成的主要工作有:坐标变换逐顶点光照。当然除了这两个工作之外,顶点着色器还可以输出后续阶段所需的数据。

            如下图所示:

UnityShader入门精要阅读笔记

 

GPU在每个输入的网格顶点上都会调用顶点着色器。顶点着色器必须进行顶点的坐标变换,需要时还可以计算和输出顶点的颜色。例如,我们可能需要进行逐顶点的光照。

 

           坐标变换:顾名思义,就是对顶点坐标进行某种变换。也就是我们可以在这一步对顶点对位置信息进行操作,模拟类似水面或者布料,但无论我们在顶点着色器中如何修改坐标对位置,一个最基本的顶点着色器必须完成的一项工作就是:把顶点坐标从空间模型转换到齐次裁剪空间

           关于齐次裁剪空间,这里有个腾讯学院的拓展阅读:https://gameinstitute.qq.com/community/detail/117556

           下图展示了这样的一个转换过程:    

        

      UnityShader入门精要阅读笔记

  

  裁剪由于我们的场景可能会很大,而摄像机的视野范围可能不会覆盖所有的场景物体,裁剪就是为了将那些在摄像机视野范围外的物体去除而被提出来的。

        一个图元和摄像机的关系有三种:完全在视野内、部分在视野内、完全在视野外。完全在视野内的就传递给下一个流水线阶段,完全在视野外的就不会向下传递,而部分在视野内的就需要进行一次处理,就是裁剪。

  下图展示了一个裁剪的过程:

                UnityShader入门精要阅读笔记

  只有在单位立方体的图元才需要被继续处理。因此,完全在单位立方体外部的图元(红色三角形)被舍弃,完全在单位立方体内部的图元(绿色三角形)将被保留。和单位立方体相交的图元(黄色三角形)会被裁剪,新的顶点会被生成,原来在外部的顶点会被舍弃 。

  和顶点着色器不同,这一步是不可编程的,即我们无法通过编程来控制裁剪的过程,而是硬件上的固定操作,但我们可以自定义一个裁剪操作来对这一步进行配置。

 

  屏幕映射:

              UnityShader入门精要阅读笔记