初识Unity Shader
本系列参考《Unity Shader入门精要》,记录学习笔记以备复习
本篇介绍的是渲染流水线各阶段的概念
渲染流水线
输入是一个虚拟摄像机、一些光源、一些shader以及纹理
输出渲染一张二维纹理
分为三个阶段:应用阶段(Application Stage)、几何阶段(Geometry Stage)、光栅化阶段(Rasterizer Stage)
GPU流水线上一些可高度编程的阶段,而由着色器编译出来的最终代码是会在 GPU上运行的(对于固定管线的渲染来说,着色器有时等同于一些特定的渲染设置);
有一些特定类型的着色器,如顶点着色器、片元着色器等;
依靠着色器我们可以控制流水线中的渲染细节,例如用顶点着色器来进行顶点变换以及传递数据,用片元着色器来进行逐像素的渲染。
应用阶段
准备好场景数据
粗粒度剔除(culling)工作,以把那些不可见的物体剔除出去
设置好每个模型的渲染状态。
输*:渲染所需的几何信息,即**渲染图元(rendering primitives)**。通俗来讲,渲染图元可以是点、线、三角面等。这些渲染图元将会被传递给下一个阶段——几何阶段。
应用阶段大致可分为下面3个阶段:
把数据加载到显存中。
设置渲染状态。
调用Draw Call
渲染状态
定义了场景中的网格是怎样被渲染的。例如,使用哪个顶点着色器(Vertex Shader)/片元着色器(Fragment Shader)、光源属性、材质等。如果我们没有更改渲染状态,那么所有的网格都将使用同一种渲染状态。
Draw Call
实际上,Draw Call就是一个命令,它的发起方是 CPU,接收方是GPU。这个命令仅仅会指向一个需要被渲染的图元(primitives)列表,而不会再包含任何材质信息——这是因为我们已经在上一个阶段中完成了
几何阶段
通常在GPU上进行
几何阶段负责和每个渲染图元打交道,进行逐顶点、逐多边形的操作
几何阶段的一个重要任务就是把顶点坐标变换到屏幕空间中,再交给光栅器进行处理
输出:屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息,并传递给下一个阶段。
光栅化阶段
GPU 上运行
光栅化的任务主要是决定每个渲染图元中的哪些像素应该被绘制在屏幕上。
它需要对上一个阶段得到的逐顶点数据(例如纹理坐标、顶点颜色等)进行插值,然后再进行逐像素处理。
GPU流水线
GPU的渲染流水线实现。颜色表示了不同阶段的可配置性或可编程性:绿色表示该流水线阶段是完全可编程控制的,黄色表示该流水线阶段可以配置但不是可编程的,蓝色表示该流水线阶段是由GPU固定实现的,开发者没有任何控制权。实线表示该Shader必须由开发者编程实现,虚线表示该Shader是可选的
顶点着色器
输入:来自cpu
处理单位:顶点
完成工作:坐标变换和逐顶点光照。
把顶点坐标从模型空间转换到齐次裁剪空间,然后由硬件做透视除法,得到归一化的设备坐标
裁剪
剔除不在视野内的物体,只需要将图元裁剪到单位立方体内
屏幕映射
任务:把每个图元的x和y坐标转换到屏幕坐标系下,一个缩放的过程。输入坐标范围是-1和1之间,对于输入的z坐标不做任何处理。
屏幕坐标系和z坐标一起构成了一个坐标系——窗口坐标系,这些值会一起传递到光栅化阶段。
屏幕坐标系差异:opengl左下角作为最小坐标,directx定义左上角为最小坐标 (0,0)
下面开始进入光栅化阶段
输入:屏幕坐标系下的顶点位置以及额外信息:z,normal,viewdir etc.
光栅化目标:计算每个图元覆盖像素,计算颜色
三角形设置
计算三角网格表示数据的过程,得到三角形边界的表示方式
三角形遍历
也称为扫描变换,检测每个像素是否被一个三角网格覆盖,如果被覆盖的话,生成一个片元。
片元中的状态是通过对三个顶点的信息进行插值得到的。
片元着色器
directx中称为像素着色器。
输入:上一阶段对顶点信息插值的结果
输出:一个或者多个颜色值
仅可以影响单个片元
逐片元操作
directx中称为输出合并阶段。
任务:
决定每个片元的可见性,包括深度测试,模版测试 测试顺序不唯一,可以提前深度测试
片元通过测试后需要将其颜色与存储在颜色缓冲区中的颜色混合。
对于不透明物体可以关闭混合操作。对于半透明物体需要使用混合操作使其看起来是透明的。
当模型的图元通过上述计算和测试后就会显示在屏幕上。GPU使用双重缓冲技术,保证看到的图像是连续的。
何为shader?
具体来说,shader就是:
GPU上可高度编程的阶段
有一些特定类型的着色器
依靠着色器我们可以控制流水线中的渲染细节