渲染管线概念篇
渲染管线概念
渲染是一个非常复杂的过程,它需要从一系列的顶点、纹理等信息出发,把这些信息最终转换成屏幕图像,而在这个过程中,需要CPU和GPU密切配合,这一个过程也叫渲染流水线。
什么是渲染流水线?
渲染管线也叫渲染流水线。流水线是并行进行的,可以大大提高生产的效率。图形渲染过程也同样使用了该技术,CPU并不需要等待GPU完成后才执行下一步操作。
而渲染管线(流水线)总的来说就是将数据分阶段的变为屏幕图像的过程。
这里面指的数据又如下几点
1.顶点数据:模型的顶点坐标、法线向量、纹理坐标等等。
2.纹理数据:纹理贴图等。
3.光照数据:光照参数、光源信息等。
还有其他的Unity场景上相关的数据。
渲染流水线中的分阶段
渲染管线一共分为3个阶段:
应用阶段(CPU) ——> 几何阶段(GPU) ——> 光栅化阶段(GPU)
在每一个阶段都会对数据进行处理。
最终目的就是在屏幕上让我们看见最终的图像。
CPU与GPU相关知识
CPU:中央处理器,负责算数运算、逻辑操作、数据传输等通用计算任务,同时还管理和调度计算机的资源(游戏开发中—游戏逻辑处理)。
GPU:图形处理器,是专门用于图形和并行计算的处理器显卡就是搭载GPU的硬件设备,显卡包含一个或多个GPU芯片,还包含显存(用于存储图像数据)、显示接口、视频解码器等等(游戏开发中—渲染相关处理)。
CPU主要处理操作系统管理、程序执行、通用计算等等。
GPU主要处理图形渲染、图像处理等等。
应用阶段(CPU)
应用阶段最重要的是输出渲染所需要的几何信息,即渲染图元。
渲染图元
在渲染管线中,图元是指几何数据的基本单元。
它是构成几何体的最小可绘制的单元。
图元可以是点、线、三角形,在渲染管线的几何阶段,顶点数据会被组合为图元。
这些图元将在后续的光栅化阶段转换为像素,最终呈现在屏幕上。
应用阶段一般都干了什么?
1、不可见的物体数据剔除,比如视椎剔除、遮挡剔除、层级剔除等规则。
2、准备好模型相关数据(顶点、法线、切线、贴图、着色器等等),将数据从硬盘加载到系统内存中,然后网格、纹理等数据又被加载到显存中。
3、设置渲染状态(设置网格需要使用那个着色器、材质、光源属性等等)。
4、调用DrawCall(CPU通知GPU使用相关的数据和渲染状态进行渲染)。
调用DrawCall
DrawCall就是一个渲染命令。
这个命令仅仅会指向一个需要被渲染的图元列表。
几何阶段与光栅化阶段(GPU)
渲染管线的几何阶段主要由GPU主导,因此我们无法拥有绝对的控制权,但是GPU为我们开放了部分控制权。
几何阶段:主要做的事情是根据应用阶段输入的数据信息进行顶点坐标转换到屏幕空间中、裁剪不可见图元以及输出空间二维顶点坐标、每个顶点对应的深度值、着色等相关信息。
光栅化阶段:主要做的事情是根据几何阶段输入的信息计算每个图元覆盖哪些像素,以及为这些像素计算他们的颜色以及哪些像素应该被绘制在屏幕上。
顶点着色器
它处理来自应用阶段由CPU传递过来的顶点相关数据,输入进来的每一个顶点都会调用一次顶点着色器中的逻辑。
顶点着色器需要完成的工作主要有:
1、坐标变换 —— 顶点变换、法线变换、纹理坐标变换等。最基本的就是把顶点坐标从模型空间转换的齐次裁剪空间。
2、顶点属性处理 —— 对顶点的其他属性进行处理,比如顶点颜色、透明度、切线向量等,可以用于实现顶点动画、着色、光照等效果。
3、顶点插值 —— 计算顶点属性的插值值。等等
例子:一般可以通过改变顶点位置来模拟水面、布料等。
曲面细分着色器(可选着色器)
属于一个可选着色器,用于细分图元。主要是对三角面进行细分,以此来增加物体表面的三角面的数量。借助它可以实现细节层次LOD(Level of Detail)的机制,使得离摄像机越近的物体具有更加丰富的细节,而远离摄像机的物体具有较少的细节。性能优化的一种方式。
几何着色器(可选着色器)
用于执行逐图元的着色操作,或者产生更多的图元。与顶点着色器不能销毁或创建顶点不同,几何着色器是可以创建或销毁几何图元。根据输入图元类型扩展为一个或更多其他类型的图元,或者不输出任何图元。比如,几何着色器的一个拿手好戏就是将一个点扩展为一个四边形(即两个三角形)。
作用:能够剔除和修改输入的图元,也能生成新的图元。典型应用包括在网格的轮廓边拉伸毛发(法线可视化)、动态几何体形成(LOD)、动态镶嵌、把线段以分形细分模拟闪电效果、布料模拟等。
裁剪
裁剪阶段会自动的将不在视野内和部分在视野内的图元(点、线、三角形)进行裁剪,我们可以进行一些配置,但是一般我们不需要进行任何处理,渲染管线会自动帮助我们进行处理。
屏幕映射
把每一个图元的x和y坐标转换到屏幕坐标系下,而对输入的z坐标不做任何处理。(这个坐标系也叫窗口坐标系)
而屏幕映射得到的屏幕坐标决定了这个顶点对应的屏幕上哪个像素以及距离这个像素有多远。
三角形设置
几何阶段输入到光栅化阶段的数据主要是三角形网格的顶点信息,我们得到的只是三角形网格每条边的两个端点信息。
如果想要得到整个三角形网格对像素的覆盖情况,就必须计算每条边上的像素坐标,为了能计算三角形边界像素的坐标信息,我们必须得到三角形边界的表示方式。
在三角形设置这个小阶段,GPU主要做的事情就是计算三角形网格的表示数据
三角形遍历
该阶段主要根据三角形设置中计算出的三角形网格数据,检查每个像素是否被一个三角形网格所覆盖,如果覆盖的话,就会生成一个片元(包含屏幕坐标、深度、法线等等信息)。
这个阶段也被称为扫描变换
在三角形遍历这个小阶段,GPU主要做的事情就是根据三角形网格信息得到被它们覆盖的片元序列
什么是像素、片元?
像素:
像素是计算机图形学中的基本概念,它是组成图像的最小可控单位。
具有位置和属性,用于表示图像中的颜色和其他信息。
它是二位图像中的一个点,每个像素都占据屏幕上的一个固定位置。
比如我们常见的显示器分辨率为:1920 x 1080,就表示宽度为1920个像素,高度为1080个像素。
片元:
在渲染管线中,片元是指在光栅化阶段生成的像素或像素片段,片元是渲染管线中进行像素级别操作和计算的基本单位。
每个片元代表了屏幕上的一个像素,并且具有位置信息和与之相关的属性。
储存一系列信息,比如:颜色、深度值、法线、纹理坐标等等。
片元着色器(像素着色器)
它主要完成对三角形遍历输入的片元序列中的每个片元(像素)的着色计算和属性处理。
片元着色器需要完成的工作主要有:
1、光照计算 —— 计算片元的光照效果。
2、纹理映射 —— 根据片元在纹理中的位置,对纹理进行采样,将纹理颜色映射到片元上,实现表面贴图效果。
3、材质属性处理 —— 根据材质的属性,比如颜色、透明度、反射率等,计算片元的最终颜色和透明度。
4、阴影计算 —— 根据光源等信息,计算片元是否处于阴影中,影响其最终颜色。等等
逐片元操作(输出合并阶段)
它主要完成对片元着色器输出数据(最终颜色、法线、纹理坐标、深度等)进行各种处理和计算。
逐片元操作主要完成的工作主要有:
1.决定每个片元的可见性,比如深度测试、模板测试。
2.如果通过了所有测试,需要把片元的颜色值和已经存储在颜色缓冲区(屏幕显示的就是颜色缓冲区的颜色值)的颜色进行合并(混合)。等等
模板测试:
模板测试(Stencil Test)是一种高级渲染技术,它通常用来限制渲染的区域。
比如一些高级的用法,如渲染阴影,轮廓渲染,镂空等等。举个例子:在实现门户效果(如传送门)或镜子效果时,模板测试可以确保只有在特定区域内的物体被渲染。
其中的比较完全可以由开发者指定,例如小于是舍弃该片元,或者大于等于是舍弃该片元。
深度测试:
通过深度测试来实现前面的物体遮挡后面的物体。
它通过将深度缓存中的值和当前片元的深度进行比较,计算是否需要更新深度缓存和颜色缓存,如果不需要则将该片元丢弃,如果通过了,可以由开发者决定是否用这个片元的深度来覆盖原有的深度,通过开启/关闭深度写入来实现。
混合:
当我们执行这次渲染时,颜色缓冲区往往已经有了上次渲染之后的颜色结果,那么,我们这次是使用这次渲染结果覆盖之前结果,还是其他处理,比如透明效果。
补充
逻辑上来说这些测试是在片元着色器之后进行的,但是大多数GPU来说,他们尽可能在执行片元着色器之前执行这些测试。因为当你发现GPU花费的好大力气计算出片元的颜色后,却发现这个片元根本就没有通过测试,要被舍弃,徒劳无功。比如下面长方体中间一大片区域根本没有通过深度测试。所有一般测试在片元着色器之前执行,当然会出现某些冲突情况,GPU会自行判断,冲突则会自动关闭提取测试。
当模型的图元经过了上面层层计算和测试后,就会显示到我们的屏幕上。我们的屏幕显示的就是颜色缓冲区中的颜色值。但是,为了避免我们看到那些正在进行光栅化的图元,GPU会使用双重缓冲(Double Buffering)的策略。这意味着,对场景的渲染是在幕后发生的,即在后置缓冲(Back Buffer)中。一旦场景已经被渲染到了后置级冲中,GPU就会交换后置缓冲区和前置缓冲(Front Buffer)中的内容,而前置缓冲区是之前显示在屏幕上的图像。由此,保证了我们看到的图像总是连续的。
CPU、图像应用编程接口(OpenGL/DirectX)、显卡驱动和GPU之间的关系
引用
[1] UnityShader入门精要
[2] 唐老狮Shader入门教程