渲染引擎光栅化基础

三角形网格

从传统上来说,游戏开发者会使用三角形网格来为表面建模。三角形是表面的分段线性逼近,如同用多条相连的线段分段逼近一个函数或曲线。
渲染引擎光栅化基础_第1张图片
实时渲染之所以选用三角形,是因为三角形:

  • 是最简单的多边形
  • 必然是平坦的。前三个顶点能定义一个平面,第四个顶点或许会位于该平面之上或者之下
  • 经多种转换后仍然是三角形。在最坏情况下,从三角形的边去观看,三角形会退化为线段。其他情况下仍能维持三角形的形状
  • 几乎所有商用图形加速硬件都是为三角形光栅化而设计的

缠绕顺序

三角形由三个顶点的位置矢量定义。每条棱的相邻顶点的位置矢量相减,就能求得3条棱的矢量。任何两条棱的叉积,归一化后都能定义为三角形的单位面法线N。我们通过缠绕顺序(顺时针还是逆时针),确定面法线的方向,从而确定哪一面是三角形的正面而哪一面不是。
渲染引擎光栅化基础_第2张图片
多数底层图形API提供了基于缠绕顺序来剔除背面三角形的方法(位于三角形背面的那个面不被渲染)。重要性在于不需要浪费时间渲染看不见的三角形。而且渲染透明物体的背面还会造成视觉异常。

三角形顶点存储

定义网格的最简单方法就是以每三个顶点为一组列举,每三个顶点对应一个三角形。
实际上这里面有许多重复的顶点,为此可以采用更有效率的数据结构——索引化三角形表,即每个顶点仅列举一次,然后用轻量级的顶点索引(16位)来定义顶点。前者被称为顶点数组/顶点缓冲,儿后者会存储于另一单独缓冲,称为索引数组/索引缓冲。
渲染引擎光栅化基础_第3张图片
当然有两个特殊的网格结构,不需要建立索引缓冲也能起到优化顶点存储的作用,分别是三角形带/三角形扇。三角形带即是第一个三角形的三个顶点后面接着一个新顶点,这个顶点与它的前两个顶点形成一个新三角形(为了保证缠绕顺序一致,前两个相邻顶点会互换次序);三角形扇即是第一个顶点与之后每个顶点和其前一个顶点都能围成一个新三角形。
渲染引擎光栅化基础_第4张图片

描述表面的视觉性质

光和颜色

渲染照相写实影响的关键在于正确地模拟光和场景中物体交互作用时的行为。光通常做4件事:

  • 光可被吸收(一个平面只会吸收某个波长的光,其他波长的光会被反射)
  • 光可被反射(漫反射或者镜面反射)
  • 光可在物体中传播,过程中通常会被折射
  • 光会被衍射
    衍射通常因为在多数场景中衍射的效果并不明显而被忽略。

顶点属性

要描述表面的视觉特性,最简单的方法就是把这些特性记录在表面的离散点上。
每个顶点包含部分或以下所有特性:

  • 位置矢量。通常是模型空间的坐标表示。
  • 顶点法矢量。顶点位置上的表面单位法矢量。
  • 顶点切线矢量。和顶点副切线矢量、顶点法矢量垂直。
  • 漫反射颜色。
  • 镜面颜色。
    通常存储在C struct、C++类的数据结构中,被称为顶点格式。比如:
    渲染引擎光栅化基础_第5张图片
    渲染三角形时,我们需要的时三角形内每像素的属性,而非每顶点属性。最简单的方法就是对没顶点属性进行线性插值。

纹理

如果三角形比较大,那么以逐顶点设置表面性质可能太过粗糙,顶点插值也并非总是我们想要的。比如三角形细分和不细分下的镜面高光表现:
渲染引擎光栅化基础_第6张图片
可以用纹理贴图的方式来解决顶点表面属性的限制,类似纹身贴在手臂上的效果。把纹理当作是存储数据的独立表格,,定义一个称为纹理空间的二维坐标系,通常以两个归一化的数值表示,从左下角(0,0)伸展至右上角(1,1)。每个三角形顶点设置纹理坐标,就能把三角形映射至纹理空间的平面上。
纹理坐标可以延伸到(0,0)~(1,1)之外,有多种方式处理之外的坐标:

  • 缠绕模式:纹理在各个方向上重复
  • 镜像模式:与缠绕模式相似,但是会形成镜像
  • 截取模式:在正常范围外简单地延伸
  • 边缘颜色模式:用户指定一个颜色,范围外用这个颜色代替
    渲染引擎光栅化基础_第7张图片
    纹素(纹理中的每个像素)和其所占屏幕像素的比值被称为纹素密度。纹素密度越大代表单位屏幕像素内有很多纹素,这会造成这些纹素都会影响到单个屏幕像素的显示,比如莫列波纹:
    渲染引擎光栅化基础_第8张图片
    而且还会浪费内存(没人能看见细节);密度小于1会察觉到纹素的边缘,破坏真实感。
    于是有mipmap(多级渐远纹理)技术来解决这个问题:对于每个纹理,建立较低分辨率位图的序列,其中每张的宽度和高度是前一张的一半。比如64x64的纹理会被分成:
    渲染引擎光栅化基础_第9张图片

材质

包括贴到网格表面的纹理设置,以及其他高级特性(选用哪个着色器、着色器的输入参数。。。)
顶点属性并不算是材质的一部分。网格和材质结合后包含所有需要渲染物体的信息。
三维模型通常会使用多个材质。比如人类模型有头发、皮肤、眼睛、牙齿等。

光照基础

局部及全局光照模型

渲染引擎使用多种数学模型来模拟光和表面/体积的交互作用,被称为光传输模型。
最简单的模型只考虑直接光照:光发射后,碰到场景中某个物体后反射,然后直接进入虚拟摄像机的虚拟平面,被称为是局部光照模型,此模型中不会考虑物体对其他物体的光照影响。
要想达到真正的照相写实,就必须考虑间接光照:光被多个表面反射后进入摄像机。全局光照模型几乎可以完全用单一数字公式:渲染方程/着色方程描述。

phong氏光照模型

此模型把从表面反射的光分解为3个独立项。

  • 环境
  • 漫反射
  • 镜面反射
    渲染引擎光栅化基础_第10张图片
    如上图,前三个因素加起来得到最后一张成果图。

透视和正视

使用透视投影渲染场景时,观察体积的形状是截断的四角锥体;当使用正射投影时,观察体积就是长方体。
渲染引擎光栅化基础_第11张图片

光栅化

在屏幕上产生一个三角形的影像,就需要给该三角形范围内的像素填充数据。这个过程称为光栅化。
光栅化可能会遇上这样一个情况:两个重叠的三角形渲染时,并不知道要怎么渲染。有一个画家算法,即是哪个三角形在前面就渲染哪个。当然如果两个三角形交叉时就不能这么做。
要正确的实现三角形遮挡关系,就要使用深度缓冲技术。每个像素含24位整数(或少见的浮点数)的深度数据。每个片段含z坐标表示深度。哪个离摄像机更近,即深度越浅,就渲染谁,即把这个像素的颜色和深度写进帧缓冲,反之则抛弃。
如果渲染两个非常接近的平行平面,可能会存在深度相等的情况(如果精度不够高,那么10.1和9.8就都会深度表示为10),可能会出现较远的平面像素覆盖较近的平面像素的情况,即深度冲突。为了尽量防止这个现象发生,应当采用观察空间的z坐标而非齐次裁剪空间的z坐标。首先解释齐次裁剪空间的z坐标,是观察坐标的倒数。这会导致离摄像机越远时,两个齐次裁剪z坐标的距离越近。比如两个三角形的观察空间z坐标是3和4,转换成齐次裁剪空间后显然会比观察空间z坐标是9和10转换后的距离要大(1/3-1/4>1/9-1/10),则后者更容易出现深度冲突的问题。
渲染引擎光栅化基础_第12张图片
所以我们更应该去选择线性变化的观察空间z坐标(被称为w缓冲)而非这种非线性变化的齐次裁剪空间z坐标。

你可能感兴趣的:(游戏,unity,游戏引擎,架构,图形渲染)