您的位置:首页 > 移动开发 > Unity3D

[Unity3D]Shader学习笔记之渲染流水线

2016-08-27 16:22 363 查看
渲染流水线的最终目的是在于生成或者说是渲染一张二维纹理,Shader仅仅只是其中的一个环节。

流水线的概念

生产一个产品需要三个步骤ABC,每个步骤用一个单位时间,且每个步骤只能在前一个步骤完成后才能继续进行,这样生产一个产品需要三个单位时间。

Created with Raphaël 2.1.0非流水线AABBCC111

如果引进流水线,那么当A交给B后将不必等待C的完成,而继续A的下一次生产,这样生产过程近乎于并行的,所以生产一个产品需要一个单位时间。如果每个步骤的耗时不同的话,生产一个产品的时间则为耗时最长的步骤所用的时间。

Created with Raphaël 2.1.0流水线AABBCC1122

渲染流水线

应用阶段 (Application Stage)

通常由CPU负责实现,这一阶段最重要的是输出渲染所需的信息,即渲染图元(Rendering primitives)

最要有三个步骤:

1. 准备场景数据:使用了哪些模型及光源等。

2. 然后剔除(Culling):为了提高性能,剔除不可见的物体。

3. 最后设置每个模型的渲染状态:材质、纹理、Shader等。

几何阶段 (Geometry Stage)

通常由GPU负责实现,负责和每个渲染图元打交道,进行逐顶点、逐多边行的操作。最重要的是把顶点坐标变换到屏幕空间中。最后将输出屏幕控件的二维顶点坐标、每个顶点对应的深度值、着色器等相关信息。

光栅化阶段 (Rasterizer Stage)

通常由GPU负责实现,使用上一个阶段传递的数据来产生屏幕上的像素。主要任务是决定每个渲染图元中的哪些像素应该被绘制到屏幕上。它需要对上一个阶段得到的逐顶点数据(例如纹理坐标、顶点颜色等)进行差值,然后进行逐像素处理。

CPU和GPU之间的通信

渲染流水线的起点是CPU,即应用阶段。应用阶段大致可分为下面3个阶段:

把数据加载到显存中。

设置渲染状态。

调用Draw Call。

把渲染所需的数据加载到显存中:显卡对于显存的访问速度更快,而且大多数显卡对于RAM没有访问权限。

Created with Raphaël 2.1.0硬盘HDD内存RAM显存VRAM

设置渲染状态:状态定义了场景中的网格是怎样被渲染的。如果没有更改渲染状态,那么所有的网格都将使用同一中渲染状态。

调用Draw Call:CPU通过调用Draw Call来告诉GPU开始进行一个渲染过程。一个Draw Call会指向本次调用需要渲染的图元(Primitives)列表,而不会包含任何材质信息。 当给定了一个Draw Call时,GPU就会根据渲染状态(例如材质、纹理、着色器等)和所有输入的顶点数据来进行计算,最终输出成屏幕上显示的像素。

GPU流水线

CPU通过Draw Call来命令GPU进行渲染,GPU的渲染过程就是GPU流水线。

Created with Raphaël 2.1.0顶点数据曲面细分着色器几何着色器剪裁屏幕映射三角型设置三角形遍历片元着色器逐片元操作屏幕图像

几何阶段

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

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

几何着色器(Geometry Shader):可选着色器,用于执行逐图元(Per-Primitive)的着色操作,或着被用与产生更多的图元。

剪裁(Clipping):可配置的,将那些不在摄像机视野内的顶点剪裁掉,并剔除某些三角图元的面片。

屏幕映射(Screen Mapping):不可编程和配置的,负责把每个图元的坐标转换到屏幕坐标系中。

顶点着色器

是流水线的第一个阶段,它的输入来自CPU。

处理单位是顶点,输入进来的每个顶点都会调用一次顶点着色器。

顶点着色器本身不可以创建或者销毁任何顶点,而且无法得到顶点与顶点之间的关系。

主要工作是坐标变换和逐顶点光照。

坐标变换:把顶点坐标从模型空间转换到齐次剪裁空间。可改变顶点的位置,顶点动画等。

剪裁

图元和摄像机的关系:

完全在视野内:传递给下一个流水线阶段

部分在视野内:不会继续传递,不需要被渲染

完全在视野外:进行剪裁,视野外的顶点应该使用一个新的顶点来代替,这个新的顶点位于边界的交点处,原先不可见的顶点则会被舍弃。

是不可编程的。

屏幕映射

任务是把每个图元的x和y坐标转换到屏幕坐标(Screen Coordinates)。

屏幕坐标系和z坐标一起构成了一个坐标系,叫做窗口坐标系(Window Coordinates)。

屏幕坐标系差异:

OpenGL:左下角为(0,0)

Direct3D:左上角为(0,0)

光栅化阶段

三角形设置(Triangle Setup)和三角形遍历(Triangle Traversal):固定函数(Fixed-Function)阶段。

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

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

三角形设置

计算光栅化一个三角网络所需的信息。

目标是计算每个图元覆盖了哪些像素,以及为这些像素计算它们的颜色。

三角形遍历

检查每个像素是否被一个三角网络所覆盖,如果被覆盖的就生成一个片元(Fragment),这个过程也称为扫描变换(Scan Conversion)。

输出的到片元序列。一个片元不是真正意义上的像素,而是包含了许多状态的集合,这些状态用于计算每个像素的最终颜色。

片元着色器

非常重要的可编程着色器阶段。在DirectX中又被称为像素着色器(Pixel shader)

这一阶段可以完成许多重要的渲染技术,如纹理采样。

输入是上一个阶段对顶点信息插值得到的结果,输出是一个或多个颜色值

逐片元操作

逐片元操作是OpenGL中的说法,在DirectX中称为输出合并阶段(Output-Merger)

这一阶段主要任务:

决定每个片元的可见性。这涉及到许多测试工作,例如深度测试、模版测试等。

如果一个片元通过了所有的测试,就需要把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行合并,或者说是混合。

Created with Raphaël 2.1.0片元模版测试深度测试混合颜色缓冲区

模版测试 (Stencil Test)

如果开启了模板测试,GPU会首先读取(使用读取掩码)模版缓冲区中该片元位置的模版值,然后将该值和读取(使用读取掩码)到的参考值(Reference value)进行比较,这个比较函数可以是由开发者指定的。如果这个片元没有通过这个测试,该片元就要会被舍弃。

深度测试 (Depth Test)

如果开启了深度测试,GPU会把该片元的深度值和已经存在于深度缓冲区中的深度值进行比较。如果这个片元没有通过这个测试,该片元就要会被舍弃。

混合 (Blend)

对于不透明的物体可以关闭混合,这样片元着色器计算的到的值就可以直接覆盖掉颜色缓冲区的像素值。

但对于半透明物体需要开启混合。如果开启了混合,GPU会取出源颜色和目标颜色,将两种颜色进行混合。源颜色指的是片元着色器的到的颜色值,而目标颜色则是已经存在于颜色缓冲区中的颜色值。之后就会使用一个混合函数来进行混合操作,这个混合函数通常和透明通道相关。

双重缓冲 (Double Buffering)

当模型的图元经过了层层计算和测试后,就会显示在屏幕上。屏幕显示的就是颜色缓冲区中的颜色值。但是为了避免看到那些正在进行光栅化的图元,GPU会使用双重缓冲的策略。

这意味着,对场景的渲染是在幕后发生的,即在后置缓冲(Back Buffer)中。一旦场景已经被渲染到了后置缓冲中,GPU就会交换后置缓冲区和前置缓冲(Front Buffer)中的内容,而前置缓冲区是之前显示在屏幕上的图像。由此保证了看到的图像总是连续的。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息