渲染流水线计算机需要从一系列的顶点数据,纹理等信息出发,将这些信息最终转换成一张人眼可以看到的图像。
这一渲染过程分成三个阶段:
1. 应用阶段 :由开发者主导的阶段。例如,开发者使用了哪些数据,模型,光源等。通常在CPU负责实现。
2. 几何阶段: 处理所有和我们要绘制的几何相关的事情。例如,决定绘制的图元是什么,怎么绘制,在哪绘制等。通常在GPU上进行。
3:光栅化阶段:使用上一阶段传递的数据来产生屏幕上的像素,并渲染出最终的图像。在GPU上进行,主要任务是决定每个渲染图元中的哪些像素应该被绘制在屏幕中。
CPU和GPU之间的通信
1. 将数据加载到显存
所有的渲染所需的数据都需要从硬盘中加载到系统内存,然后,网格和纹理等数据又被加载到显卡上的存储空间———显存。
2. 设置渲染状态
通俗的解释,这些状态定义了场景中的网格怎么被渲染,例如使用了那个顶点着色器/片元着色器,材质等。如果不变更渲染状态,所有的网格都使用同一种渲染状态。
3 调用Draw Call
Draw Call 其实就是一个CPU发起,GPU接收的一个命令。这个命令仅仅会指向一个需要被渲染的图元列表。当给定一个Draw Call是,GPU就会根据渲染状态和所有输入的顶点数据来计算。最终输出成屏幕上显示的像素。
GUP流水线
调用Draw Call命令GPU进行渲染的过程就是GUP流水线。
以下为渲染顺序流程:
顶点数据——》顶点着色器——>曲面细分着色器——》 几何着色器 ——》裁剪——》 屏幕映射——》三角形设置——》 三角形遍历——》 片元着色器——》 逐片元操作——
——》屏幕图像
(红色标记为几何阶段中分成的更小的流水线,绿色为光栅化阶段中分成的更小的流水线)。顶点数据的输入也就是之前小节《CPU和GPU之间的通信》的过程。
主要流水线阶段解释:
顶点着色器
是完全可编程的,用于实现顶点的空间转换,顶点着色等功能。
主要工作:坐标变换和逐顶点光照。
裁剪
就是不在摄像机视野范围的物体不需要被处理。(不可编程)
屏幕映射
把每个图元的x和y坐标转换的屏幕坐标系下(二维坐标系)
三角形设置(开始进入光栅化)
计算光栅化一个三角形网格所欲的信息。(具体来说,上一阶段得到的是三角网格每条边的两个端点,要得到整个三角形的像素覆盖情况,必须计算每条边上的像素坐标)
三角形遍历
根据上一个阶段计算结果判断一个三角形网格覆盖了哪些像素,被覆盖的话就生成一个片元。
片元着色器
非常重要的可编程着色器阶段,用于实现逐片元的着色操作
逐片元操作
主要任务:
决定每个片元的可见性。(设计很多测试工作)
如果通过了测试,就需要将这个片元的颜色和已经存储的颜色合并。
逐片元操作时可以配置的,我们可以配置每一步的操作细节。
困惑解答:
1. 什么是OpenGL/DirectX?
2 什么是HLSL, GLSL, CG?
3 什么是Draw Call?
4 为什么Draw Call 多了会影响帧率?
每次调用Draw CallDraw Call之前,CPU会向GPU发送很多内容,包括数据,状态和命令等,这一阶段CPU要完成很多的工作。
Draw Call 过多会浪费CPU大量的时间,造成过载。
5如何减少Draw Call?
这里仅讨论批处理。
优化的想法其实就是将很多小的Draw Call合并成一个打的Draw Call,这就是批处理思想。需要注意的是,由于我们需要在CPU的内存中合并网格,
而合并的过程是需要消耗时间的,因此批处理技术更加适合静态的物体。
什么是固定管线渲染
最后,明白什么是shader了吗?shader所在的阶段就是渲染流水线的一部分,具体来说,shader就是:
--- GPU流水线上一些课高度编程的阶段,而由着色器编译出来的最终代码是会在GPU上运行的。
--- 有一些特定类型的着色器,如顶点着色器,片元着色器等。
--- 依靠着色器我们可以控制流水线中的渲染细节,例如用顶点着色器来进行顶点变换已经传递数据,用片元着色器来进行逐像素的渲染。
|
|