处理器/DSP
一个渲染流程主要分为三个阶段:准备阶段,几何阶段,光栅化阶段。
准备阶段:
1 把数据加载到缓存中
2 设置渲染状态
3 调用Draw Call
GPU流水线
1.GPU的渲染流水线实现
颜色表示了不同阶段的可配置性或可编程性:绿色表示该流水线阶段是完全可编程控制的,黄色表示该流水线阶段可以配置但不是可编程的,蓝色表示该流水线阶段是由GPU固定实现的,开发者没有任何控制权。实线表示该shader必须由开发者编程实现,虚线表示该Shader是可选的.
2、CPU和GPU的通信
1)cpu的工作:把数据加载到显存,设置渲染状态,调用draw call。
把数据加载到缓存:所有数据都要从硬盘加载到系统内存,然后网格和纹理,顶点位置、颜色,法线,纹理坐标等数据加载到显存中。
设置渲染状态:使用哪个顶点着色器和片元着色器,光源属性,材质等来渲染的过程,渲染状态不改,所有网格都会使用一种渲染状态。
调用draw call:翻译过来就是绘制命令,由cpu发出,指向一个要被渲染的图元列表,通知gpu可以按照上面的设置渲染这些图元了。我们常说优化draw call,是因为cpu准备上述数据是个复杂的过程,而gpu绘制却很快,如果draw call很频繁,cpu光顾着准备数据了,gpu又空等着,结果可想而知,所以每次发出draw call,我们应该尽可能多准备数据给gpu,这样就可以用尽量少的draw call达到通知gpu快速渲染的效果。可是如何调一次draw call尽可能多准备数据给gpu呢,这需要一个专门的主题了。
2)GPU流水线
上图中绿色表示该流水线是完全可编程控制的,黄色表示可以配置但不可以编程的,蓝色表示GPU固定实现的,开发者没有控制权。虚线框表示该shader是可选的。
下面我们逐一看一下:
a、顶点着色器:写shader人员必须要面对的重点部分。顾名思义,该阶段处理的是顶点数据,重点是这里是单个顶点数据,你别想访问其他顶点数据。我们要在这里完成顶点的坐标变换,把顶点从模型空间转换到齐次裁剪空间,再经透视除法,最终得到归一化设备坐标(NDC)。还有逐顶点光照,并准备好后面阶段需要的其他数据,比如纹理坐标,顶点颜色等。
b、曲面细分着色器用于细分图元,几何着色器用于执行逐图元的着色操作,或产生更多图元,这两个阶段都是可选的。
c、裁剪:上面阶段我们得到的NDC是立方体空间,Unity,OpenGL是从(-1,-1,-1)到(1,1,1),DirectX的z是从0到1,完全在该空间内的图元保留,完全在外面的抛弃,一半在内一半在外的就需要裁剪了,这就是我们视野内的部分。该阶段是可配置的,比如我们用自定义的裁剪平面,或裁剪图元的正面或背面。
d、屏幕映射:该阶段是不可配置和编程的。这里输入的坐标是三维的,屏幕映射的任务是把每个图元的x,y坐标转换到屏幕坐标系(二维)下,前面NDC我们的x,y在(-1,1)内,所以映射到屏幕上就是个缩放的过程,而最终的屏幕坐标系会和z坐标构成窗口坐标系,传给光栅化阶段。有一点要注意,OpenGL会以屏幕左下角为最小坐标,而DirectX会以左上角为最小坐标。
e、三角形设置:不可配置和编程。从这一步开始进入光栅化阶段。上个阶段输出的都是三角形顶点,而这个阶段我们要用这些顶点和计算出来的三角形边界组成三角形网格数据。
f、三角形遍历:不可配置和编程。检查每个像素被哪个三角形所覆盖,而后生成片元,重点是三角形的三个顶点会对覆盖的每个像素的数据进行插值,比如深度和坐标等,记住这点很重要,如下图所示:
g、片元着色器:又是我们重点关心的。这个阶段是可编程的(废话),上面的阶段给我们准备好了每个片元的所有数据,这个阶段就需要发挥你的能力用这些数据输出片元的颜色了,这里注意的是和前面的顶点着色器处理的单个顶点一样,这里我们处理的是单个片元,不要去想着访问其他片元。这个阶段可以做很多重要的渲染技术,比如纹理采样,用前面插值出来的纹理坐标采样出该片元对应的纹理颜色。
h、逐片元操作:这个阶段的目的就是进行合并,是高度可配置的。有两个任务,一是经过一系列测试(模板测试、深度测试)决定每个片元的可见性,一是通过测试后留下的片元要和已存在颜色缓存区的颜色进行合并,开启混合的就混合,没开启的就直接覆盖。
经过上面的所有计算后就该显示在屏幕上了,GPU采取多重缓冲的机制,渲染会发生在后置缓冲中,渲染结束后GPU可以交换到前置缓冲来显示。
全部0条评论
快来发表一下你的评论吧 !