渲染流水线最终目的:生成或者渲染一张二维纹理,即我们在电脑屏幕上看到的所有效果。它的输入是一个虚拟摄像机、一些光源、一些shader以及纹理等。
渲染流程分为三个阶段:应用阶段,几何阶段,光栅化阶段。
应用阶段:
通常由CPU负责实现。是由开发者主导的。
开发者有3个主要任务:
- 准好场景数据。例如摄像机的位置、视椎体、场景里的模型、光源等。
- 做一个粗粒度剔除工作。把那些不可见的物体剔除出去,这样就不需要再移交给几何阶段。
- 设置好每个模型的渲染状态。包括但不限于使用的材质(漫反射颜色、高光反射颜色)、使用的纹理、使用的Shader等。
输出:渲染所需要的几何信息,既渲染图元(rendering primitives)。渲染图元可以是点、线、三角面等。
几何阶段:
负责和每个渲染图元打交道,进行逐顶点、逐多边形的操作。处理所有和我们要绘制的几何相关的事情。例如,决定需要绘制的图元是什么,怎样绘制,在哪里绘制。这一阶段在GPU上进行。
一个重要任务就是把顶点坐标变化到屏幕空间中,再交给光栅器处理。
输出:屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息。
光栅化阶段:
使用上个阶段传递来的数据产生屏幕上的像素,并渲染出最终的图像。
光栅化的任务主要是决定每个渲染图元中的哪些像素应该被绘制在屏幕上。需要对上一个阶段得到的逐顶点数据(例如纹理坐标、顶点坐标等)进行差值。然后再进行逐像素处理。
CPU和GPU通信
应用阶段大致可以分为以下3个阶段:
1.把数据加载到显存。
渲染所需的数据都要从硬盘加载到系统内存。然后,网格和纹理等数据又被加载显卡的存储空间——显存中。这是因为,显卡对于显存的访问速度更快,而且大多数显卡对于系统内存没有直接的访问权限。
2.设置渲染状态。
渲染状态定义了场景中的网格是怎么样被渲染的。例如,使用哪个顶点着色器/片元着色器、光源属性、材质等。
3.调用Draw Call。
DrawCall就是一个命令,CPU通过调用DrawCall来告诉GPU开始进行一个渲染过程。一个DrawCall会指向本次调用需要渲染的图元列表。
GPU流水线
GPU渲染的过程就是GPU流水线。
图中绿色表示该流水线阶段是完全可编程控制的,黄色表示该流水线可以配置但不是可编程的,蓝色表示该流水线阶段是由GPU固定实现的,开发者没有任何控制权。实线表示该Shader必须由开发者编程实线,虚线表示该Shader是可选的。
几何阶段
顶点着色器:
输入:来源于CPU。
处理单位:顶点。输入进来的每个顶点都会调用一次顶点着色器。
需要完成的工作:
1.坐标变换
就是对顶点的坐标(位置)进行某种变换。把顶点坐标从模型空间作换到齐次裁剪空间。
2.逐顶点光照
计算顶点的颜色
3.输出后续阶段所需的数据
曲面细分着色器
可选的着色器,用于细分图元。
几何着色器
可选着色器,用于执行逐图元的着色操作,或者用于产生更多图元。
裁剪:
可配置不可编程
去除那些不在摄像机视野范围的物体,不需要被处理。
图元和摄像机视野的关系:
1.完全在视野内
2.部分在视野内
3.完全在视野外
屏幕映射:
把每个图元的x和y坐标转换到屏幕坐标系(Screen Coordinates)。
屏幕坐标系和Z坐标一起构成了一个坐标系,叫做窗口坐标系(Window Coordinates)。
光栅化阶段
三角形设置
计算光栅化一个三角形网格所需要的信息。
为了能够计算边界像素的坐标信息,我们需要得到三角形边界的表达方式。这样一个计算三角形网格表示数据的过程就叫做三角形设置。
三角形遍历
检查每个像素是否被一个三角形网格所覆盖。如果被覆盖就会生成一个片元(fragment)。找到哪些像素被三角网格覆盖的过程就是三角形遍历。也称为扫描变换。
三角形遍历阶段还会使用三角网格的3个顶点信息对整个覆盖区域的像素进行差值。
输出:片元。
片元并不是真正意义上的像素。而是包含了很多状态的集合,这些状态用来计算最终颜色。这些状态包括但不限于它的屏幕坐标,深度信息,法线,纹理坐标等。
片元着色器:
输入:对于从顶点着色器输出的数据插值得到的。
输出:一个或者多个颜色。
工作:
1.纹理采样
逐片元操作
高度可配置
主要任务:
1.决定每个片元的可见性。这涉及到很多测试工作,例如深度测试,模板测试等。
2.将通过测试的片元颜色值和已经存储在颜色缓冲区的颜色进行混合。
模板测试:通常用于限制渲染区域。用于轮廓渲染,渲染阴影。