这里回顾GAMES101 Lecture 7,着色(光照与基本着色模型)。

课程主页:

课程作业:

课程视频:

本讲的内容如下:

  • 可见性/遮挡
    • Z-buffering
  • 着色
    • 照明和阴影
    • Graphics Pipeline

画家算法

可见性是指把许多物体放在屏幕上,由于有多个物体,所以自然涉及到顺序问题,即如何摆放物体,使得最后产生的图是“正确”的。最直观的想法是先画最远的物体,然后画次远的物体,以此类推,这就是画家算法。注意到画家算法无法处理物体相互重叠的情形:

补充:对于$n$个三角形,画家算法的时间复杂度为$O(n\log n)$。

Z-Buffer

思想

为了解决之前的问题,Z-Buffer诞生了,其思想为:

  • 存储每个样本(像素)的当前最小$z$值
  • 需要额外的深度值缓冲区
    • frame缓冲区存储颜色值
    • 深度缓冲区(z-buffer)存储深度

重要提示:

  • 为简单起见,我们假设$z$始终为正
    (更小的$z\to $更近,更大的$z\to $更远)

效果展示

Z-Buffer算法

算法流程为:

  • 初始化深度缓存为$\infty$
  • 在光栅化时:
    • for (each triangle T)
      • for (each sample (x,y,z) in T)
        • if (z < zbuffer[x,y]) // closest sample so far
          • framebuffer[x,y] = rgb; // update color
          • zbuffer[x,y] = z; // update depth
        • else
          • ; // do nothing, this sample is occluded

示例

小结

  • 复杂度:
    • $n$个三角形的时间复杂度为$O(n)$(假设每个三角形覆盖常数个像素。)
    • 这是否意味着我们在$O(n)$时间内解决排序问题?
      • 实际上我们没有进行排序,只不过对每个像素求最小值;
  • 如果以不同的顺序绘制三角形?
    • 不同顺序的结果相同;
  • 最重要的可见性算法;
    • 在所有GPU的硬件中实现;

引子

到目前为止,我们做了如下几件事情:

  • 在世界中定位物体和相机;
  • 计算物体相对于相机的位置;
  • 将物体投影到屏幕上;
  • 采样三角形覆盖;

即:

我们现在可以画出如下的图形:

但是我们期望的图形为:

缺失的部分即为着色,也是接下来讨论的内容。

着色

  • 字典:
    • 用平行线或色块使插图或图表变暗或上色。
  • 在本课程中:
    • 将材质应用于物体的过程。

后续会介绍简单的着色模型:Blinn-Phong反射模型。

观察

着色可以分为三个部分:

  • 高光项(Specular highlights)
  • 漫反射(Diffuse reflection)
  • 环境光照(Ambient lighting)

如下图所示:

着色是局部的

着色即计算在特定着色点向相机反射的光,输入为:

  • 观察方向$\mathbf v$;
  • 表面法线$\mathbf n$;
  • 灯光方向$\mathbf l$(对于许多灯光中的每一个);
  • 表面参数(颜色,光泽度,等等);

图示:

注意到没有阴影会产生(shading不等于shadow)。

后续先介绍漫反射如何计算。

漫反射

光线均匀地向各个方向散射,所有观察方向的表面颜色相同:

一个问题是接收到多少光(能量)?Lambert’s余弦定律:单位区域的能量和$\cos \theta = \mathbf l. \mathbf n$成正比:

光衰减

根据能量守恒,光源照射到单位球面上的能量为定值,所以在距离光源为$r$的能量密度为$I/r^2$(假设光源的能量为$I$):

Lambert(漫反射)着色

与观察方向无关的着色:

其中:

  • $k_d$为漫反射系数(颜色);
  • $ \max (0, \mathbf{n} \cdot \mathbf{l})$为着色点接收的能量;
  • $\left(I / r^2\right)$为着色点到达的能量;
  • $L_d$为漫反射光;

$k_d$的效果: