光栅化(Rasterization)

 目录

1、三角形的光栅化

2、反走样和深度缓冲(Antialiasing and Z-Buffering)

2.1、反走样(Antialiasing)

2.1.1、采样理论(Sampling Theory)

2.1.2、频域(Frequency Domain)

2.1.3、傅里叶变换(Fourier Transform)

2.1.4、反走样的应用(Antialiasing in practice)

2.2、  可见性和遮挡(Visibility/occlusion)

2.2.1、深度缓冲(Z-Buffering)


        在做完视图变换之后,下一步就要把物体画在屏幕上,即光栅化。

1、三角形的光栅化

        在透视投影中,如何确定近平面?通常只会给出垂直视场(或叫垂直角,vertical field-of-view

,缩写为fovY,代表可以看到的角度的范围,比如下图中两条红色虚线组成的角度,即屏幕上下两条边中点组成的角度)和宽高比(aspect ratio),我们需要根据这两个参数确定透视投影中两个平面的信息。

        如何根据垂直视场和宽高比确定l,r,b,t?下图中我们看到的是近平面。

根据三角形关系,可以得到:

        做完MVP之后该做什么呢? 我们知道,Model transformation是为了摆放物体,View transformation是为了摆放相机,Projection transformation投影变换分为正交投影(Orthographic projection)和透视投影(Perspective projection),其中正交投影是为了将长方体投影到的规范立方体中,透视投影是为了把棱锥体投影到规范立方体中。最终规范立方体我们要画到屏幕上去。那什么又是屏幕呢?屏幕是一个像素阵列,在图形学中我们可以抽象的认为是一个二维数组,数组中的每个元素是一个像素,数组的大小代表分辨率。屏幕是一种典型的光栅显示器。

        关于像素的概念,图形学中,我们认为像素是一个颜色均匀的小方块(即单独的一个小方块的颜色是一样的),像素由红、绿、蓝三种基本的颜色(rgb)组成,其他颜色是由这三种颜色按照不同的比例表示,比如一个像素的颜色是黄色的,黄色就是由红绿蓝三种基础色按照不同的比例形成的。

         在将规范立方体画到屏幕上之前,先来定义一下什么叫屏幕空间:即在屏幕上建立一个坐标系,左下角为坐标原点,往右是x轴,往上是y轴,这个定义和虎书有点区别。如下图:

屏幕空间中像素的坐标索引以(x, y)的形式存储,其中x和y都是整数。如果一个屏幕的分辨率是width×height的话,那么像素的索引范围是(0, 0)到(width-1, height-1),屏幕覆盖的范围是(0, 0)到(width, height)。像素(x, y)的中心为(x+0.5, y+0.5)。

        接下来要做的就是把规范立方体转化到(width, height)的屏幕上。先忽视z轴,只考虑xy轴。现在只需要考虑xy平面的转换:把正方形拉伸到到[0, width]×[0, height]。如下图

 拉伸的视口变换矩阵为:

即先把拉到宽度是width,高度是height,再把左下角平移到坐标原点(此时不管z坐标)。

        把规范立方体转化到屏幕上后,我们紧接着要做的就是把这些数据打散成像素。 三角形网格在图形学中应用广泛,是因为三角形有很多重要的性质:最基本的多边形、任何其他的多边形都能拆成三角形、任意三个点构成的三角形肯定是在同一个平面上、轮廓清晰(内部外部清晰)、重心插值等。

        空间中的三角形经过一系列变换到屏幕上,我们只需关注xy坐标。现在给出一个三角形,知道三个顶点的坐标,如何求出三角形的近似像素值,即判断像素和三角形的关系或者更确切的说像素的中心点和三角形的关系。现在说一个最简单的方法:采样法

        所谓采样,就是给你一个连续的函数,求不同的位置的值,即把一个函数离散化的过程。

如下面代码所示,输入不同的x,得到不同的f(x)。

for (int x=0; x<xmax; ++x){
    output[x] = f(x);
}

采样在图形学中是一个非常重要的概念,这里所说的采样是利用像素的中心点对屏幕空间进行采样。如下图,如果每个像素的中心在三角形内,则采样。

定义一个函数inside(tri, x, y),这里的tri代表给定的三角形,x、y为任意实数,不一定是整数。若点(x, y)在三角形内,返回1,不在三角形内,返回0。

for(int x=0; x<xmax; ++x)
    for(int y=0; y<ymax; ++y)
        image[x][y]=inside(tri, x+0.5, y+0.5);

         在实际操作中,可能会遇到边界问题,比如下图中的采样点,是被三角形1覆盖了呢?还是被三角形2覆盖了呢?还是同时被它们两个覆盖了呢?

在图形学中,遇到这种情况,要么不做处理,要么做特殊处理。

        在进行判断点是否在三角形内时,是否需要对屏幕内所有的像素都进行判断呢?显然是不需要的,可以通过包围盒协助我们进行判断。比如下图中蓝色区域,就叫三角形的包围盒。如果点不在包围盒内,更不可能在三角形内了。

         通过包围盒,可以减少光栅化的工作量。通过增量三角形导线(Incremental Triangle Traversal)方法,可以帮助我们更快的实现光栅化。该方法适用于狭窄的三角形和旋转后的三角形(即三角形细长,而且经过旋转,导致包围盒很大)。如下图:

 针对三角形的覆盖区域,每一行我们都找它的最左边和最右边的点,这样的话就会大大较少比较范围。

2、反走样和深度缓冲(Antialiasing and Z-Buffering)

2.1、反走样(Antialiasing)

        通过光栅化,我们可以得到所有在三角形内的像素,如下图,但是这明显和我们想要的结果不符,我们得到的图形有明显的锯齿,存在走样问题。锯齿产生的原因是由于像素本身有一定的大小,而我们的采样率不够高。走样问题也是光栅化过程中致力于解决的一个重要问题。

 2.1.1、采样理论(Sampling Theory)

        采样可能会导致各种各样的问题,统称为瑕疵(sampling artifacts),比如锯齿、摩尔纹、车轮错觉等。导致这些问题的原因是由于信号变化太快(高频),但是采样太慢。

        为了解决反走样问题,我们在采样前先进行模糊(Blurring)或者叫预滤波(Pre-Filtering)处理。

        如下图,我们对屏幕上像素的中心进行采样,在三角形内的点用红色表示,在三角形外的点用白色表示,采样后得到的点有的在三角形内,有的在三角形外。

         现在我们拿到一个三角形,先进行一个模糊操作,然后在用像素的中心点去进行采样,得到的三角形离边界进颜色浅,离边界远颜色深。

         下面是进行反走样和没做处理的效果对比(上图没做处理,下图进行模糊处理):

        先进行模糊或预滤波处理(过滤高频信号),再进行采样,能很好的解决锯齿问题。但是如果我们先进行采样,再进行模糊处理能不能解决锯齿问题呢?答案是不能。比如下图的波函数,我们采样后,如果把采样点重新连起来试图恢复原形状,得到的结果和原始形状差别很大。

2.1.2、频域(Frequency Domain)

        下图中正弦波和余弦波,它们的唯一区别是相位不同。

        通过调整x前面的系数,可以得到不同的正弦和余弦波。它们之间的区别在于频率不同,即下图中的f。其周期为频率分之一,即1/f。

 2.1.3、傅里叶变换(Fourier Transform)

        傅里叶级数展开:任何一个周期函数,都可以写成一系列正弦函数和余弦函数的线性组合和一个常数项。 

        如下图,加上得到右边第一行右边的图形,可以近似代表box函数。如果再在的基础上减去,得到第二行右边的图形,相比第一行得到的图形,更加接近原始图形。继续在的基础上再加上,得到第三行右边的图形,相比第二行,更加接近原始图形。再在的基础上减去,得到第四行右边的图形,相比第三行,更加接近原始图形。假如我们继续加到无限多项,得到的图形将会无限接近原始图形。这就得到一个结论,用傅里叶级数展开,可以将一个函数描述成很多不同的正弦函数和余弦函数的和。

        傅里叶变换其实就是把函数变成不同频率的段。下图中,有5个不同的函数,从上到下的频率越来越高。假如我们用相同的采样方法,对下面的函数分别进行采样。我们会发现,把低频信号采样的点连起来,大概可以知道原来的函数的波形。把对高频信号采样的点连起来,就会发现和原来的函数波形相差甚远。这就是高频信号采样不足产生的走样问题。

         现在有下图中的一个波函数,我们现在对它进行采样,用黑色线把采样点连接起来。可以看到恢复的波形和原函数差别很大。

        从另一个角度考虑,假如我们有两个函数:蓝色波形表示的函数和黑色波形表示的函数(此时黑色波形函数不再是我们采样后恢复出来的函数)。两个函数上的空心圆点,是我们用同样的采样对两个函数进行采样得到的点,对两个函数采样的结果是完全相同的。这种同样的采样方法采样两种不同频率的函数,得出我们无法区分的结果的现象就叫走样。

         现在说下滤波(Filtering)的概念,从频域的角度上说所谓滤波就是去除某些特定的频率。傅里叶变换可以帮我们把一个函数从时域变到频域。如下图,通过傅里叶变换可以把左边的图像(时域)变成右边的图像(频域)。

         右边图像中心是最低频的区域,四周是高频区域。我们通过亮度表示在不同频域上包含的信息,可见大多数信息都表现在低频域上(中间最亮)。

        通过滤波,把上图中低频信号过滤掉(称为高通滤波,只允许高频信号通过),得到下面一副图片。

        如果把高频信号过滤掉(称为低通滤波,只允许低频信号通过),得到的图片如下图所示:

         若同时过滤掉低频信号和高频信号,只保留中频信号,得到的图片效果为:

         关于滤波,从另外一个角度来分析,滤波等于平均(Averaging),也等于卷积(Convolution)。什么是卷积呢?比如有下图中的信号,滤波器就像一个窗口一样,可以左右滑动,窗口的大小有三个格子,信号中按照滤波器对应的格子进行点乘,得到计算结果写回到窗口的中心值。

        卷积有个卷积定理(Convolution Theorem):时域上对两个信号进行卷积,对应到两个信号的频域上,等于频域上两个信号的乘积。

        我们拿到一张图片后,我们可以直接做卷积和,也可以先做傅里叶变换得到频域,再对频域做卷积和,对得到的结果再做逆傅里叶变换。两个方式得到的结果是一样的。

 2.1.4、反走样的应用(Antialiasing in practice)

        超采样反走样(Antialiasing By Supersampling, MSAA):通过对一个像素内的多个位置进行采样(可以看成把一个像素分成多个小的像素,比如下图中,可以看成把像素划分成4X4的小像素,来进行采样),并对其值取平均值来近似一个像素盒滤波器的效果。

         MASS算法示意图:

        MSAA虽然可以一定程度的缓解走样的问题,但是由于计算的点增加,所以增加了计算成本。如果把一个像素分成4X4来计算,就增加了16倍的工作量。

2.2、  可见性和遮挡(Visibility/occlusion)

        前面针对一个三角形,分析了如何进行光栅化。实际中,空间中会有很多的三角形,它们距离相机的距离也不同,如何把这些三角形画到屏幕上,并且体现出它们之间的层次感(近的要遮挡住远的),就是要讲的可见性和遮挡的知识。

        我们可以参考油画家创作一幅画的方法去实现(画家算法),先画远处的物体,再画近处的物体,近处物体把远处的物体遮挡住。

但是这个画家算法无法处理物体相互遮挡的情况。

为了解决这个问题,可以通过深度缓冲来实现。

2.2.1、深度缓冲(Z-Buffering)

       深度缓冲的思路是:深度缓存是针对像素而言的算法。以像素为单位,准备一个深度缓存器(z-buffer,二维数组或者是另一张图),z-buffer初始化为最大深度∞。依次渲染所有的物体(和顺序无关,所以不用考虑先后顺序)。检测每个像素点的z值,和z-buffer的值作比较,将z-buffer中的值更新为较小的那个值。

注:在变换的时候,我们是把相机放到原点,然后往负z的方向看,这样z的值都是负的,z值小,说明离我们远,z值大说明离我们近。在这里为了简化计算,我们提出深度的概念,深度可以理解为点到相机的距离。这时我们认为z都是正的,即小z代表离相机近,大z代表离相机远。

伪代码如下:

for(each triangle T) //循环每个三角形
    for(each sample(x,y,z) in T) //循环每个采样点
        if(z < zbuffer[x,y]) //同一个像素点,如果离相机更近
            framebuffer[x,y] = rgb; //更新颜色
            zbuffer[x,y]; //更新深度

举例如下图:

注意:n个三角形(假设覆盖范围固定,比如都是50个像素)的时间复杂度是O(n),复杂度那么低是因为我们没有对三角形进行排序,只是要最小值。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值