计算机图形学入门(三): 光栅化(深度测试与抗锯齿)

995 阅读4分钟

图片走样

我们简单的根据像素的中心点是否在三角形内部来判断是否着色, 最终得到的结果如下图所示:

20210429094118

这张图片有什么问题? 简单来说, 这张图片走样了, 出现了一定程度的失真. 我们来看下下面这张图:

20210429094636

造成的效果就是图片出现了锯齿, 给人的感觉就是图片不清晰.

出现这种情况的原因是: 采样频率过低而导致的走样. 了解更多关于采样的指示, 请查看图形学基础 - 着色 - 采样理论.

20210429095329

蓝色线为原始信号, 黑色线为采样信号, 空心小圆为采样点, 可以看到, 由于采样频率过低, 而导致采样信号与原始信号的不一致.

图片走样本质上也是这个问题. 如果我们提高采样频率, 比如说提高屏幕分辨率, 那么我们得到的图片当然也更清晰.

采样频率过低也叫做欠采样(undersampling).

采样频率过低可能导致的问题:

  • 锯齿(空间上欠采样)
  • 摩尔纹(空间上欠采样)
  • 马车轮效应(时间轴上欠采样)

摩尔纹的出现也是空间上欠采样的结果:

20210429100715

马车轮效应是电视画面中当汽车在前进时,车轮却在反转的现象或停止的状态, 这是一种在时间轴上欠采样的现象, 因为在序列图像中帧率低于轮子的转动速度.

20210429100739

反走样

刚刚讲到, 通过提高屏幕分辨率来提高采样频率. 但如果屏幕分辨率固定, 我们还有什么办法来提高图片质量吗?

20210429104255

我们可以先对三角形进行模糊操作再进行采样.

下面介绍一种具体的实现方式: 超采样.

超采样

20201016150244

超采样基本原理: 根据这个像素被三角型覆盖的面积占比, 决定这这个像素要显示的颜色, 占比多颜色就深, 占比少颜色就浅. 如下图所示, 第一行表示的是像素被覆盖的面积占比, 第二行表示的对应的像素颜色深浅.

20210429111454

但是要计算面积占比并不是是否容易, 所以我们介绍一种近似计算的方法, 这种方法我们称为超采样.

超采样的基本思想是, 将一个像素逻辑上划分为多个小的像素, 每个小的像素就是的中心就是一个采样点, 如下图展示的是把一个像素划分为16个小像素.

20201016151100

20201016151137

对于每个采样点, 我们可以判断它是否在三角形内.

20201016151317

那么对于一个像素, 我们就可以知道在这个像素中, 有多少采样点在三角形内, 有多少采样点没有在三角形内, 这样我们就可以近似的得到三角形覆盖这个像素的的面积占比, 我们用明暗不同的颜色表示.

20201016151609

在最终显示的时候, 就可以根据近似的面积占比决定该像素的颜色.

采用了超采样的效果图如下:

20210429111956

深度测试

当两个三角形在屏幕上重叠时, 我们该如何显示, 直觉上我们都知道, 一定是离照相机近遮挡离照相机远. 就像我们画画一样, 先画远的物体, 再在之上画近的物体. 如下图所示:

20210429135424

在图形学中我们该怎么实现呢? 下面介绍一种名为z-buffer的算法.

z-buffer

  • 存储当前每个像素的最小z值
  • 为了存储每个像素的最小z值, 我们需要一个深度缓冲区(depth buffer)

所以, 目前我们需要两个缓冲区:

  • frame buffer: 存储每个像素的color值
  • depth buffer: 存储每个像素的最小z值

20210429140942

z-buffer算法用伪代码表示如下:

20210429141134

depth buffer中每个像素的初始值为∞, 表示无穷远, 然后遍历每个三角形, 根据三角行的采样点的z值判断是否更新frame buffer和depth buffer.

这个过程下图表达的更直观:

20210429141653

深度在webgl中使用

当启用深度检测的时候,WebGL会将深度信息(深度信息位于Z轴方向,所以也叫Z-Buffer)写入深度缓冲区,在绘制阶段便会根据缓冲区深度信息大小来决定物体的某个部分是否需要画出来.

所以在webgl中, 我们并不需要自己实现z-buffer算法, 我们只需要启用深度检测:

gl.enable(gl.DEPTH_TEST);