unity shader 渲染管线

GPU图形渲染管线流程

流程概述

应用程序阶段

应用程序阶段,使用高级编程语言(C、C++、JAVA 等)进行开发,主要和CPU、内存打交道,诸如碰撞检测、场景图建立、空间八叉树更新、视锥裁剪等经典算法都在此阶段执行。在该阶段的末端,几何体数据(顶点坐标、法向量、纹理坐标、纹理等)通过数据总线传送到图形硬件。

  • 工作:
    • 准备场景数据:如摄像机的位置、视锥体、场景中包含的模型、光源等
    • 粗粒度剔除:把不可见的物体剔除
    • 设置好每个模型的渲染状态:包括材质、使用的纹理、使用的Shader等
  • 输出:
    • 渲染图元:渲染所需的几何信息

几何阶段

几何阶段,主要负责顶点坐标变换、光照、裁剪、投影以及屏幕映射,该阶段基于GPU进行运算,在该阶段的末端得到了经过变换和投影之后的顶点坐标、颜色、以及纹理坐标。
光照计算属于几何阶段,因为光照计算涉及视点、光源和物体的世界坐标,所以通常放在世界坐标系中进行计算。

  • 工作:
    • 决定需要绘制的图元是什么
    • 怎样绘制
    • 在哪里绘制
  • 输出:
    • 屏幕空间的二维顶点坐标
    • 每个顶点的深度值、着色等相关信息

光栅阶段

光栅阶段,基于几何阶段的输出数据,为像素(Pixel)正确配色,以便绘制完整图像,该阶段进行的都是单个像素的操作,每个像素的信息存储在颜色缓冲器(color buffer 或者 frame buffer)中。

雾化以及涉及物体透明度的计算属于光栅化阶段,因为上述两种计算都需要深度值信息(Z 值),而深度值是在几何阶段中计算,并传递到光栅阶段的。

  • 工作:根据上个阶段传递的数据来产生屏幕上的像素,并渲染出最终的图像。
  • 输出:逐像素处理过的渲染图元。

从几何阶段到光栅化阶段:

  1. 几何阶段:变换三维顶点坐标和光照计算
    1. 将模型空间坐标(object space coordinate)通过四阶矩阵变换矩阵(world matrix)转换为世界空间坐标( world space coordinate )。
      • 进行光照计算。
      • 将模型空间下的顶点法向量转换为世界空间下的,所用的转换矩阵为world matrix的转置矩阵的逆矩阵。
    2. 将物体顶点坐标从世界空间(world space)转换到观察空间下(eye space)。
    3. 将顶点坐标从观察空间下转换到裁剪空间下(project and clip space)。
      • 投影:用透视变换矩阵把顶点从视锥体(viewing frustum)中变换到裁剪空间的规范立方体(CVV)中。
      • 图元装配(Primitive Assembly):将顶点根据原始的连接关系还原出网格结构。
      • 裁剪:在CVV中将位于视体外的场景数据去除。
    4. 将得到的完全位于视体中的场景数据映射到屏幕坐标系上。
  2. 光栅化阶段:决定哪些像素被集合图元覆盖。光栅化是将几何数据经过一系列变换后最终转换为像素,从而呈现在显示设备上的过程,光栅化的本质是坐标变换,几何离散化。
    1. 三角形设置:计算光栅化一个三角网格所需的信息
    2. 三角形遍历:检查每个像素是否被一个三角网格所覆盖,被覆盖则生成一个片元(对顶点信息插值)。
      1. 读取模型的顶点,3个3个的读,因为要画三角形。
      2. 将3个顶点两两连成线,形成三角形。
      3. 计算屏幕像素点在三角形内还是三角形外。在三角形内部的,就上色(颜色是之前算出来的),在三角形外部的,就不上色。http://www.cnblogs.com/graphics/archive/2010/08/05/1793393.html(可以通过叉积来实现,连接PA,将PA和AB做叉积,再将CA和AB做叉积,如果两个叉积的结果方向一致,那么两个点在同一测。判断两个向量的是否同向可以用点积实现,如果点积大于0,则两向量夹角是锐角,否则是钝角。)
    3. Pixel Operation
      • 纹理操作(Texture operation):根据像素的纹理坐标,查询对应的纹理值。
      • 消除遮挡面:深度测试,模版测试等。
      • 混色(Blending):根据目前已经画好的颜色,与正在计算的颜色的透明度(Alpha),混合为两种颜色,作为新的颜色输出。
      • 滤波(Filtering):将正在算的颜色通过某种滤波后输出。

HLSL、GLSL与Cg:

常见的着色语言:

  1. DirectX的HLSL:微软控制着色器编译,编译结果在不同硬件上相同,但平台有限。
  2. OpenGL的GLSL:跨平台性良好,编译结果取决于硬件供应商。
  3. NVIDIA的Cg:真正的跨平台。

DrawCall:

CPU调用图像编程接口,命令GPU进行渲染的操作。

Shader:

  • GPU流水线上一些可高度编程的阶段,由着色器编译出来的最终代码会在GPU上运行
  • 有一些特定类型的着色器
  • 依靠着色器来控制流水线中的渲染细节。