1.1:图形渲染管线 【renderPipeline】

百人计划笔记01

霜狼may的技术美术百人计划笔记~
增长知识,拓宽视野~
可能不是每章都会写笔记,但是会持续学习!
不能保证全都理解到位书写正确,有错误请及时指出!感激不尽!


渲染管线之所以叫管线,是因为它的工作流程是线性的。
我们的场景是3d的,但最终的输出呈现在屏幕上是2d的,那么这就是通过渲染管线的一系列处理,把这些元素转换成屏幕上呈现的2d图像。

🍅整体流程:

20230206234708

1.🍏应用阶段

  • 粗粒度剔除,进行渲染设置,准备基本数据,输出到几何阶段
  • 应用阶段准备的是场景,对象的基本数据:比如场景里的物体,他们的位置朝向,大小,以及物体里对应的模型里面的每一个顶点位置,法线,切线等。
  • 再比如场景光源的位置,朝向,以及基本属性; 摄像机朝向,位置等

2.🍏几何阶段

  • 顶点着色器,曲面细分,几何着色器,顶点裁切,屏幕影射。
  • 计算顶点光照,就需要知道光源位置朝向以及摄像机的位置以及朝向,还有当前顶点的世界位置
  • 又需要知道顶点在模型空间的位置,以及模型本身的位置旋转缩放等。
  • 曲面细分着色器通过现有顶点来生成更多顶点,也需要知道现有顶点的在模型信息里的位置
  • 几何着色器需要通过现有的图元来做一些几何方面的操作,生成更多的顶点和图元。比如对现有图元所在的平面生成法线,同样需要知道现有图元的顶点位置。
  • 几何阶段要为光栅化阶段准备数据,比如干掉屏幕以外的顶点(顶点裁剪),还需要把顶点位置从3d坐标空间转换到2d坐标空间,这就是屏幕映射

3.🍏光栅化阶段

  • 三角形(点、线)设置,三角形(点、线)遍历,片段着色器。
  • 拿到映射到2d空间里的顶点位置,组装成三角形,还要知道这些三角形包含了哪些2d空间的像素点。这就是三角形遍历
  • 最后对这些点使用它们包含的数据来着色,并为后面的逐片元着色准备数据

4.🍏逐片元操作

  • 裁剪测试,透明度测试,深度测试,模板测试,混合。
  • 此时操作对象就变成了光栅化操作输出的片元数据,片元可以理解成屏幕上的某一个像素点,对于这些片元我们需要进行一系列的测试。
  • 测试比如:透明度,深度和模板测试。通过测试的片元就保留起来,否则就丢弃掉。
  • 在2d屏幕坐标系当中,同一个位置上的像素点有可能会对应于多个不同的片元。
  • 那么我们可能还需要把这些通过测试的片元的颜色进行一个混合操作,从而得到像素点最终输出的颜色。

5.🍏后处理

  • 逐片元操作完成后,我们就得到了一个类似于贴图的数据保存在内存里,然后可以对这个数据做一个后处理,也可以理解成图像处理。
  • 比如:模糊,景深,高光等等

🍅CPU与GPU:

20230207001656

1.🍏应用阶段 — cpu

  • 一般是在cpu上完成的,比如说从磁盘或内存上读取模型或贴图数据,然后加载到应用程序里。
  • 比如游戏会加载模型或者贴图,在游戏场景中,首先会做一个粗粒度剔除,被遮挡的物体就不需要显示。
  • 设置基本渲染参数和状态,比如渲染ui和渲染场景它们的渲染参数和模式可能不一样。
  • 最后通过DrawCall将这些渲染所使用的数据传给GPU去处理

2.🍏几何阶段,光栅化,逐片元操作—GPU

  • 这三个阶段一般会放在GPU处理,GPU的特点是并行性比较好
  • 比如说,有模型可能有很多顶点都需要做光照或者着色计算,这些顶点它们只是数据不同,但是它们的几何运算方式是相同的,那么就可以把他们分配到GPU的不同工作单元上面去同时执行,这样速度就很快。
  • 光栅化和逐片元也是同理。

🍅每个阶段做的事情:

1.🍏应用阶段

20230207003342

  1. 准备场景数据,摄像机数据,光源/阴影数据,全局数据。
  2. 准备好数据后,需要做一些优化,比如算法加速,干掉看不到不需要渲染的物体,做一些剔除
  3. 设置渲染状态,准备渲染参数。比如由远到进渲染,还是不透明先渲染再渲染半透明,这个就是绘制顺序。对于不同的物体使用不同的shader渲染,以及输出渲染结果到什么地方,是renderTexture还是FrameBuffer,这是渲染目标渲染模式,比如成像渲染或者延迟渲染等等。
  4. 最后设置好渲染状态和参数后,我们就会调用DrawCall,把大有渲染数据的图元输出到显存去交给GPU处理。

🍇基本场景数据:

20230207004145

🍇光源和阴影:

20230207223110

🍇加速算法,粗颗粒剔除:

20230207223310

  • 摄像机视锥之外的物体是可以裁切掉的,比如判断是否在视锥内,或者与视锥是否相交。
  • 被遮挡的物体也可以剔除掉。

🍇渲染设置:

20230207223509

  • 对于不同对象使用一些合批方式,比如GPU instance或者动态批处理等等

🍇输出到显存:

20230207223855

2.🍏几何阶段:

20230207224049

🍇顶点着色器-视图变换

20230207225721

  • 对顶点做坐标系的变换,还会对他进行一定的着色操作
  • 投影变换:(为了最后做3d到2d的投影操作做准备)
    • 1.正交,远近一样大
    • 2.透视,近大远小
    • 同时投影还有一个裁剪的作用,确定该顶点是不是在视锥的远近左右上下包围平面之内

-mvp矩阵:

  • Model:模型变换,施加在模型上的空间变换,包含平移变换(translateM)、旋转变换(rotateM)、对称变换(transposeM)、缩放变换(scaleM
  • View:观测变换,施加在观测点上的变换,用于调整观测点位置、观测朝向、观测正方向;
  • Projection:透视变换,施加在视觉上的变换,用于调整模型的透视效果(如:矩形的透视效果是梯形)。

-顶点着色器还有一个作用是计算顶点光照

🍇曲面细分(可选步骤)

20230207231217

  • 按照算法生成更多顶点

🍇几何着色器(可选步骤,基于图元的操作)

20230207231347

  • 顶点着色器操作的对象是单个顶点,而几何着色器操作对象是一个图元;
  • 这个图元可能是一个顶点,也可能是一个线段,两个顶点,也有可能是多个顶点构成的连续线段,也有可能是三个顶点构成的三角形,或者其他。
  • 它的作用是通过给定图元去生成更多图元

🍇投影

20230207231658

  • 前面的步骤都是3d空间的,那么把3d空间转换到2d屏幕的转换过程,就是投影的步骤

  • 顶点在裁剪空间的位置,xyzw会对它进行一个透视除法,把xyz除以w来完成投影操作。

  • 这样就从投影坐标系转换到了标准设备坐标系,也就是NDC(Normalized Device Coordinates, NDC)

    • 一旦你的顶点坐标已经在顶点着色器中处理过,它们就应该是标准化设备坐标了,标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。
  • 正交投影上,w始终为1,所以不管在投影空间中的任意位置,xyz除以w都不会发生变换。

  • 透视模式中,w是近处比较小,远处比较大,所以说对于近处远处的点,它们xyz除以w,投影到2d平面上就会呈现出近大远小的效果

🍇裁剪

20230207233402

  • 转换后如果xyz 超过-1~1的范围,则会被剔除(处于裁剪空间外)
  • 在Open GL中,xyz三个维度都是从-1~1.
  • 而D3D当中只有xy两个维度是从-11,z则是从01

🍇屏幕映射

20230207233925

  • 屏幕是输出设备的长宽,所以这里也有一个映射过程。
  • OpenGl和D3D的屏幕坐标系原点也不一样
    • OpenGl的原点在左下方
    • D3D原点在左上方

2.🍏光栅化阶段:

20230207234142

🍇三角形设置

20230207234220

  • 知道这个图元的边界信息,而计算这个边界信息的过程就是三角形设置。然后就可以知道它覆盖的屏幕像素

🍇三角形遍历

20230207234856

  • 检查这些像素是否被三角形覆盖,如果被覆盖就说明这个片元属于这个三角形。
  • 这种寻找被三角形网格所覆盖的所有像素的过程就叫做三角形遍历
  • 得到被三角形所覆盖的所有像素后,会使用三角形的三个顶点,对每一个被覆盖的对象进行线性插值,然后得到当前三角形在像素对应片元的数据。
  • 所以这里得到的片元并不等同于是像素。

🍇抗锯齿(MSAA)

20230207235306

  • MSAA使用子采样点对三角形进行覆盖测试,看这个子采样点深度缓存里面的数值进行比较,看是否通过。

🍏逐片元操作

20230208000014

  • 对通过的片元,我们需要用什么方式混合,最终输出到一个像素;这一步是可以配置的
  • 然后将他们输出到目标缓冲区

🍇片元着色

20230208000549

  • 对于一个三角形所覆盖的片元,会使用三个顶点数据,对其进行线性插值。
  • 如p点就是三个顶点进行线性插值的结果。我们还可以得到其他如UV信息,深度信息等数据
  • 然后再用片元数据和其他全局数据,比如光照阴影时间等等去计算,得到最终的片元颜色

🍇颜色混合,透明度测试

20230208001154

🍇颜色混合-深度测试、模板测试

20230208001351

  • 深度测试的测试对象就是片元的深度值,把片元深度值和对应的深度缓冲当中的深度值去比较,通过比较的会保留下来
  • 模板测试比较模板值,我们希望对两个立方体进行描边,不希望任何一个立方体描边挡住其他的立方体,那么我们可以将两个立方体的顶点放大一点,并且将它绘制成描边的颜色。
  • 然后我们进行真实立方体绘制的时候,我们会把立方体的模板值和之前描边颜色的模板值比较;模板值是描边模板值的,我们把它覆盖掉,这样就可以实现立方体永远在描边之上。
  • 这个比较方式也可以配置,可以是小于通过也可以是大于通过,也可以是等于通过。

🍇混合

20230208002257

  • 逐片元最后一个操作

🍏后处理

20230208002742