GAMES101-Lecture-7~9 着色

现代计算机图形学入门-闫令琪,课程笔记。

Lecture 7~9: Shading 着色

在图形学中,所谓着色,就是对不同物体使用不同材质的过程 (The process of applying a material to an object)。

物体表面的颜色受光照和材质的影响,光照中光线的颜色也在一定程度上决定物体表面的颜色。着色就是计算物体表面最终该如何显示的这么一个过程。

着色模型 Shading Model

简单来看,当光照射到物体上时,会有三种表现:高光(镜面反射)、哑光(漫反射)、环境光。如果我们能模拟出类似的表现,着色也就实现了,对于这三种情况我们分别建立不同的数学模型来进行计算。

在此之前我们先定义一些要用到的概念:

  • shading is local:我们考虑物体的着色情况,考虑的是单位面积对于入射光的表现,不考虑阴影(如果物体被遮挡,那入射光类型就是环境光)。
  • 因为这个单位面积的范围极小,可以视作平面(微积分),所以我们只需考虑平面情况;
  • 所谓法线,就是垂直于这个平面的直线;

哑光(漫反射 Diffuse)

漫反射(只考虑理想状态):当光照射一点时,光线均匀的反射至各个方向,此时无论从哪个方向看物体,都是同样的颜色。

理想状态下的漫反射我们采用的是 Lambertian Reflectance(朗博反射/理想散射/朗博余弦定理)数学模型,这是一个理想状态下的简单模型,并不完全符合物理定律。

  1. Kd:一个系数,表示物体对于光能的吸收率;
  2. I/r²:光的衰减/光能与距离的关系;
  3. max(0, n · l):入射方向与法线的夹角;
  4. Ld:最终值,值越大亮度越大。
_Kd 值越大,反射出的光线越多,物体表面看上去越亮_
_假设光均匀传播,光能与距离的平方成反比。物体离光源越近,亮度越大_
_入射方向与物体表面夹角不一样,吸收的光能多少也不一样,亮度也就不一样_

高光(镜面反射 Specular)

高光:接近于镜面反射。当观察方向与光的反射方向很接近时才能看到高光。

此时计算是否显示高光,其实就是计算向量 V 与 R 的夹角,使用的是 Phong Reflectance Model。但是这个计算很麻烦,人们对其进行了改进,叫 Blinn-Phong Reflectance Model

Blinn-Phone 模型很巧妙的将计算位置改到了向量 h 与法线 n 的夹角。而向量 h 可以由向量 l 和 n 点乘获得,很方便计算。

  • 此公式中其他参数与漫反射模型中一致
  • p指数代表可以看到高光的范围。一般采用 100 < p < 200,可视角度大概在 3°.
_p 指数越大,可以看到高光的范围越小(x 轴)_

环境光 Ambient

环境光的模型比较简单,主要是为了保证视野内不是一片黑色。

最后,这三种情况叠加在一起,就是我们在着色时使用的模型:

着色频率 Shading Frequencies

_三种不同的着色频率(方式)_
  1. 方式一:面着色 (Flat shading)。根据每个平面的法线来确定颜色。
  2. 方拾二:顶点着色 (Gouraud shading)。根据每个顶点的法线来确定颜色,平面的颜色根据顶点的值使用插值算法求得。
  3. 方式三:像素着色 (Phong shading)。根据每个像素的法线来确定颜色。(注意,与 Blinn-Phong Reflectance Model 不是一个东西)

三种方式渲染方式最终效果并没有高低之分,渲染条件不一样,结果也不一样,需要根据不同情况来进行选择。如下图所示,当物体切割的层面无限多时,最终效果是差不多的。

图形管线 Graphics Pipeline

所谓图形管线其实就是从开始建立三维场景到渲染出最终图像的整个过程(类似于生命周期),这个过程中有几个主要操作步骤。

  • 输入三维的点 > 投影到屏幕上 > 点与点连线形成三角形 > 三角形光栅化,离散为片元 > 着色 > 显示
  • 这整个流程是在硬件里面写好了的
  • 为什么第一步确定的是顶点?
    • 三角形投影变幻之后的形状可能会改变,也就是点的位置会改变,确定了顶点,投影之后连线就可以了。
  • 现代 GPU 有可编程的渲染管线,可以让用户来决定每个步骤如何执行

纹理映射 Texture mapping

纹理贴图本质上在做一个什么事情?

物体是三维的,但物体表面是二维的。我们可以制作这么一张图片,图片上的每个点与二维表面的每个点一一对应,那么这张图就可以完美的贴在物体表面。这就是纹理贴图要做的事。

贴图上的每个点与二维表面的每个点的对应关系,就是纹理映射。

如上图所示,图中玩具球上所有的点使用的是同一个着色模型,但是表现出来的颜色并不一致。根据着色模型公式的推导我们知道,表现不一致是因为不同点的着色系数不一样(图中红色字体),那么每个点的着色系数我们是需要单独保存的。推广开来,我们可以为每一个点保存一组参数来表示这个点的属性,所有属性综合起来才是这个点最终的表现结果。 映射时用到的一些属性,我们同样可以保存在点的那组参数里。

贴图是二维的,其上的每一个点都可以使用直角坐标 (u, v) 来表示。贴图中每个小三角形顶点的数据我们已经有了,三角形中间的数据,需要使用插值的方式来计算出来。

三角形插值 Interpolation Across Triangles

插值(Interpolation),是一种通过已知的、离散的数据点,在范围内推求新数据点的过程或方法。利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。

我的理解:插值与采样相反,采样是已知连续只取部分,插值是已知部分求连续

插值的方式有很多种,这里我们用的是线性插值。如下图,如果已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1] 区间内某一位置 x 在直线上的值,其实就是求出 (x0, y0) 与 (x1, y1) 可能的函数曲线,然后带入 x 求得 y,此时求得的 y 值虽然有误差,但是是一个非常近似正确的值。

_线性插值示意图_
  • 为什么使用三角形插值?
    • 着色时候很多操作是在三角形的顶点进行的,我们希望通过顶点的值获得三角形内部每个点平滑过渡的近似值;
  • 希望插值哪些内容?
    • 纹理坐标,颜色,向量 …
  • 如何插入?
    • 三角形的重心坐标(线性插值)
    • 其实还有其他插值方式,常用的是线性插值;

什么是重心坐标?

前面我们有讲过单位向量(长度为一,只表示方向),在笛卡尔坐标系中 X 轴 Y 轴的单位向量又叫做基向量,所有的向量都可以表示为 Sx*i + Sy*j 。如下图所示:

也就是说,在笛卡尔坐标系中,任何的向量都是基向量 i, j 进行缩放后相加的结果,这一概念肥肠重要。

我们把这个概念拓展一下,脱离直角坐标系,不再局限于 X 轴和 Y 轴上,而是可以在整个平面内随意移动和缩放,此时如果用 v, w 来表示基向量,那么我们就可以用 Sv*v + Sw*w 来表示这个平面上的任意一个向量!当这个向量的起点是原点时,Sv*v + Sw*w 表示的就是任意一个点。

有了这一个概念,我们看下图这个更直观的例子,在非直角坐标系中,将 abc 看做是三角形的顶点,a 看做原点,a 到 b 和 a 到 c 的向量分别是基向量,α, β, γ 为缩放倍数,那么任一点 p 可以表示成:

  • p = a + β(b-a) + γ(c-a)
  • 移项得到:p = (1-β-γ)a + βb + γc
  • 定义一个新变量α,使得 α = 1-β-γ
  • 此时 p = αa + βb + γc
  • (α, β, γ) 就称为点 p 的重心坐标

好的,我们回到刚刚讨论的三角形。知道啥叫重心坐标了,如何计算 α,β,γ 的值呢?直接给出,不做推导了。

_任意一点重心坐标 (α, β, γ) 的计算公式_

重心坐标是计算插值的一种方式,我们只要将三个顶点 ABC 中已知的值作为常量带入上面的计算公式,就可以得到三角形内所有像素点的重心坐标(α, β, γ 的值),也就是这一点的插值!这个“已知的值”可以是三个顶点的任意属性:color、depth、material attributes …

注意:三维物体上的三角形投影到二维,重心坐标有可能会改变,所以如果想计算一些三维属性的插值,应该取三维空间中的顶点属性再去计算得到的结果才是正确的!

纹理应用 Applying Textures

现在我们可以获得三角形上每一个点的属性插值了,同样也就能够获取贴图的 (u, v) 坐标了,获取之后去贴图的二维直角坐标系上查询对应的 (u, v) 坐标赋值即可。当然,在应用的过程我们会遇到问题。

遇到的问题

Q:第一个问题,当显示器的分辨率很大,但贴图却很小的时候该怎么做?
A:打补丁的事当然少不了插值🤣可以使用双线性插值和双立方插值法来计算插值。如下图,红点位置考虑周围四个点的情况,先水平方向线性插值,后垂直方向。

Q:第二个问题:当显示器分辨率低,贴图太大怎么办?
A:本质是像素覆盖的纹理面积太大,会产生走样和锯齿。

  • 解决方式一:Supersampling 更多的采样
    • 太浪费
  • 解决方式二:范围查询
    • 采样引起的误差,那就不采样了,直接求范围内的平均值
    • 常用的 Mipmap:速度快,只能做正方形的近似查询,有误差
_第一张为原始贴图,后续的每张图在前一张的图上像素数减小一半_
_Mipmap 图像金字塔_

Mipmap 带来的问题:过度模糊。因为只能取贴图正方形内的近似值,可像素部分的贴图对应在贴图的 uv 坐标上不一定是正方形,这就会造成偏差增大,结果就是远处的元素过渡模糊。

怎么解决呢?常用的是 EWA filtering:不规则图形分解成多个圆环,进行多次查询求得更准确的近似值。当然,多次计算会耗费更多性能。No free lunch…

使用场景

  • General method to bring data to fragment calculations Many applications
  • Environment lighting
    • 物体对于光照的交互可以生成一张图保存起来
    • 常用的有 Spherical Map、Cude Map
  • Store microgeometry
  • Procedural textures
  • Solid modeling
  • Volume rendering