Games101 Z-Buffer and shading part 1


回顾:上节课里面我们讲了光栅化,光栅化是将几何数据经过一系列变换后最终转换为像素,从而呈现在显示设备上的过程,我们以一个三角形为例,如何画在屏幕上:

  • 屏幕就是一堆像素,每个像素是一个小方块,且小方块内的颜色具有唯一性.
  • 我们用像素中心对三角形覆盖这么一个信号做采样,也就是我们利用像素中心来判断一个像素是否在三角形内.但是得到的是以下图形,出现了锯齿现象.
    在这里插入图片描述
  • 因此我们需要进行抗锯齿(反走样),一个方法是通过更换更高分辨率的显示器来减少锯齿,另一个则是我们用MSAA,FXAA.TAA来进行反走样. 以MSAA来说原理就是,我们先对其进行一个模糊操作,在进行采样就会得到一个没有锯齿的三角形.

到此,我们将一个三角形画在了屏幕上,但是显示处理中我们是多个图形交叠在一起,他们会存在遮挡关系,且近处的永远会遮住远处的,这是该如何处理呢?

画家算法

我们要把多个物体放在屏幕上,肯定会存在一个顺序关系,先放什么后放什么,这样图像才看起来正确不突兀.那么我们会先放上远处的物体,然后再放近处的物体,按一个从远到近的顺序将图给"画出来",从而得到一个正确的结果.这也是油画家们创作作品时候的思路和顺序.
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在上图中,先放上山,然后放上草地从而遮盖了一部分山,再放上树,从而遮盖了一部分草地.

我们将其带入到图形学中:

  • 我们有一个场景,先把场景里远处的东西光栅化在屏幕上,然后近处在做光栅化
  • 若此时新光栅化的与已经光栅化的物体若产生重叠,则新光栅化的会覆盖住已经光栅化的
  • 等场景中所有物体按照从远到近的顺序光栅化完,我们就得到了一个具有遮盖的结果.

这就是画家算法

如果要求你画一个立方体,按照画家算法来操作,我们先光栅化出最里面那个面,然后依次是,左面,
右面,下面,上面,最后是前面,就得到了一个立方体.

在这里插入图片描述在这里插入图片描述
前面和后面的顺序我们可以知道,但是四条侧边的顺序呢?如果我们按照里面,右面,上面,左面,下面,前面的顺序进行的话,我们会在看到图中的红线部分,因为左面是后画的,因此他会遮盖住上面的部分,这就不会得到一个正确的结果.也就是我们无法定义"深度"这一概念,
在这里插入图片描述
如果按照画家算法对物体的深度进行排序我们需要O(n log n)次,排序完之后按照顺序将物体光栅化.但是出现下图情况时:

在这里插入图片描述
这三个三角形,两两存在覆盖关系从而形成了一个环,也就是在深度上存在互相遮挡关系,此时我们无法定义其深度关系,无法定义谁在前谁在后,因此我们无法对其进行排序,也就是我们无法用画家算法.此时我们引入深度缓存这个概念.


Z-buffer

既然我们无法对于几何图形进行排序,那么我们就从像素方面考虑.因此引入Z-BUFFER算法:

z缓冲是当前使用较多的深度测试的方法,先声明一些问题:

  • 由于相机是放在坐标原点指向-z轴(屏幕里面的),因为我们看到的z都是负的,因此一个物体的z的坐标越小,这个物体离我们就越远;z的坐标值越大,离我们就越近。

  • 但是这里我们计算物体所处的深度时不这么取值,因为深度只能是一个大于0的数,所以我们取z的绝对值作为一个物体的深度。此时Z越大,则离我们越远,Z越小,则离我们越近.

e.g:
在这里插入图片描述
如图所示,左图为frame buffer,右图为depth buffer(Z-BUFFER),两图是同时生成的.frame buffer用来存储最终渲染的结果,depth buffer则存储每个像素点的深度值(z).
在Z-BUFFER上,一个像素的深度值越大,则点越白,也就是离我们远.Conversely,一个像素的深度值越小,则点越黑,离我们也就近.(我们设取色范围为0-1,color = 0为黑,color = 1 为白,当我们的深度值小,对应的颜色值也就小,因此就接近黑色;当我们的深度值大,对应的颜色值也就大,因此也就接近于白色).
在这里插入图片描述
我们以图中鼠标所指处为例,所指处存在一个像素点,我们在绘制图像时,先绘制了地板,地板占用了此像素点,此时我们记录下地板的深度值,然后在绘制立方体时,立方体也占用了这个像素点,又记录下此时的深度值,然后发现立方体的深度值比地板的深度值要小,那么就在这个像素点上绘制立方体从而来覆盖地板==,也就是每个像素点上只保留深度值最小,深度值大的会被深度值小的所覆盖.==

深度缓冲的算法(Z - Buffer Algorithm)

在这里插入图片描述

  • 先把所有像素的深度值都初始化为无限大
  • 然后对于每个三角形而言
  • 对于三角形上的每一个像素点
  • 如果这个像素点的深度值小于深度缓冲中的深度值
    {
    在该像素点绘制深度值小的所在三角形的rgb颜色
    然后更新深度缓冲的深度值为当前绘制的三角形的在该点的深度值
    否则
    就什么都不做。
    }
    直白点来看就是:
    在这里插入图片描述
    上图为深度图,R代表无穷,其中的数字代表了深度值.
    渲染结果(frame buffer)和深度图(depth buffer)都是同步的进行的,因此在更新时也是同步更新的.

深度缓冲的时间复杂度(Z - Buffer Complexity)

  • 对于n个三角形而言,其时间复杂度为O(n)

  • 因为这个算法并没有对三角形进行排序之类的工作,只是对在每一个像素上进行了一个判断,如果深度值小就写入,如果深度值大就什么也不做。比如说有三个覆盖100个像素的三角形,对这三个三角形所作的工作就是将其深度值与深度缓存比较,一个一个像素填入,所做的操作次数就是 3 * 100。所以时间复杂度其实就是 = 三角形的个数 × 每个三角形覆盖的像素的数。是一个O(n)的时间复杂度。

如果按照不同的顺序,用z - buffer 进行绘制三角形,会有什么效果?
假设我们先绘制紫色三角形,然后在绘制红色三角形,那么得到的结果与先绘制红色在绘制紫色得到的结果一样,**结果不受影响,因为Z-BUFFER只记录所绘制图形的深度,和绘图的顺序没有关系.**但在真正实际操作中并不是对每个像素进行深度值统计,例如在MSAA中对于每个像素分成的更小的采样点也会进行统计,因此其实是对每个采样点进行深度值得比较。


到此,我们的光栅化部分彻底结束,接下来将会进行shading的内容:


Shading

到目前为止我们都学了什么?

在这里插入图片描述

  • 先对空间中拜访物体(Modeling transform,左上)
  • 然后将相机变换到原点的位置,并且旋转其指向方向(viewing transform, 右上)
  • 然后在相机的角度,对物体进行投影到屏幕上(projection transform,左下)
  • 最后进行光栅化,将物体绘制在屏幕上(右下)。

在经过以上四步之后,我们可以得到类似以下例子的一个结果:
在这里插入图片描述
但我们实际上想要得到的是这样的结果:
在这里插入图片描述

我们从之可以发现,两幅图中,相差的效果就是缺少了着色的操作,图二在进行着色操作之后显得更加真实。
那么,什么是着色呢?

Shading

着色的定义:通过平线性或者色块在图中引入不同的明暗和颜色。*
在这里插入图片描述
drakening:引入明暗的不同,也就是有的地方明亮一些,有的地方暗一些。
coloring:有的地方有颜色,有的地方有不同的颜色,有的地方没有颜色。
而我们在图形学上,我们对其定义是:对不同的物体应用不同的材质进行着色。
假设我们有一个球,它可以是石膏球,可以是木头球或者木头球,他们之间形状一样,但是材质不一样。不同的材质和光线的相互作用方法肯定也不一样。因此我们将着色与材质放在一起讲。

一个简单的着色模型(Blinn - Phong Relectance Model)

在这里插入图片描述

光源在右上的方向,光源照亮了所有的茶杯,可以看到茶杯上有一些颜色不同的地方

  • 可以看到茶杯上有一个 高光(Specular highlights), 高光是由于光线照射到了光滑的表面,其光线反射方向接近镜面反射方向,因此形成了高光。

  • 茶杯表面除了高光外,其余颜色变化并不剧烈的地方,我们称之为漫反射(diffuse reflection)

  • 光源在右上,在茶杯的背面应该看不到这个光源,那么茶杯的背面应该是黑色。但是我们看到了这个茶杯的背面并不是黑色,也就是说有一些的光从茶杯的背面反射到了我们的眼里,那么这个点一定是接受到了光。但是这个点接受到的并不是直接光照,而是间接光照。比如说光找到墙上,墙面发生了一个漫反射将光反射到了桌面上,光再经过桌面的反射就能到茶杯的背面。假如说任何一个点都能够接收到来自四面八方的反射光,这个反射光就是环境关照(Ambient lighting),且这个光是一个常亮.

着色点的光照

首先,我们需要定义一些东西:

  • 观察者的方向向量 (Viewer direction ) --------- v
  • 着色点所在表面的法向量(Surface normal )--------- n
  • 光线照射的方向向量(Light direction )--------- l
  • 着色点表面的一些参数(颜色,材质,反光度等)
  • 三个向量均为单位向量.

在这里插入图片描述

光照具有局部性(Shading is Local)

在这里插入图片描述
我们在考虑一个点的着色情况时,我们只看点自己,最多考虑一下光照和观测方向,不考虑阴影。(Shading != Shadow)

如图,我们可以知道光照时在左侧,因此模型应该会产生阴影,但是我们不考虑光线是否被其他物体遮挡,因此不考虑阴影问题。我们这里着色能够得到的效果只有物体表面上的光照效果。

漫反射(Diffuse Reflection)

在这里插入图片描述
当光线打到平面上一个点时候,光线会均匀的反射到各个不同的方向上去,这就是漫反射。

漫反射与观察者的位置没有关系,引文漫反射是向四面八方均匀的反射光纤,所以观察者不管从什么角度观察,表面的颜色都是一样的。

物体接受光线能量的方式

同样的光以不同的角度照在同样的表面上,得到的明暗程度是不一样的。
在这里插入图片描述
我们假设光是离散的,我们可以用不同的光线来代替,每根光线的能量是一样的,其亮暗程度其实就是接受了多少光照的能量。

从图我们可以看出,当光照与物体表面垂直时候,可以接受到光的全部能量,因此会十分的亮。

当物体旋转了一定角度时候,图中是当光与物体成60度时候,只能接受到一半的能量,因此会显得稍微暗淡。

因此我们可以得出一个结论,物体表面的法线和光线的夹角决定了物体表面的亮暗程度,但这是通过观测得到的结论是一个经验,并非科学的理论。

更科学的解释是这样的:首先考虑光是一道能量,这就说明我看到了一个物体就代表着这些物体接收到了一定量的能量。

比如说用太阳能板接受太阳光,太阳能板越大,接收到的光照的能量就越多。如果要考虑一个着色点能接受多少能量,那么就要看这个着色点周围的单位面积能接受到多少能量,但是着色点周围的单位面积始终是不变的,那就要考虑法向量和光线的夹角。考虑一下下面的情景:为什么地球会有冬天和夏天,并不是因为夏天离太阳近一些,冬天离太阳远一些。其实是因为当北半球在夏天时,太阳对北半球的光线是一个直射的状态,这个光照几乎时垂直北半球,这就说明夏天和冬天区别就是看光线是否垂直于我们所处的地球表面,这也就解释了为什么北半球是夏天时,而南半球是冬天,当光线直射北半球的时候,就不能直射南半球,南半球单位面积接收的光线的能量也就更少。

所以在图形学中,一个shading point附近的单位面积接受到的光线的能量是和光线的入射方向有关的。

计算从不同角度接受到的光线能量有一个Lambert’s cosine law(兰伯特余弦定理)。

这个定理是说,接收到的光线的能量和 光线方向Shading point的角度的**cos值成正比。**比如,当法线方向与光线方向一样,也就是直射时,COS为1,此时最亮。

当光线垂直于物体表面时,物体表面所能够接收到的光线的能量最大,而当光线垂直于物体的表面的法向量时,物体表面就不能接收到光线的能量,也就会非常暗。

光衰减(Light Falloff)

我们提到了接收能量,就要提一下发散。光是一种能量,设想一下我们有一个如下图所示的点光源,点光源无时无刻以一定速度朝四面八方发射光能量。

在这里插入图片描述
我们假设上图中的光是在真空中传播,光在传播过程中没有能量的损失。我们以球壳的方式来表现光向外发射能量的过程,即在某一时间点上,所有光线的终点可以围城一个球体。

由于光线在传播过程中没有能量损失,结合能量守恒定律,那么在每一个球壳上的能量的大小应该是相同的,即在靠近光源的一个小的球壳上所包含的光的能量应该是和外面的大的球壳上所包含的光的能量是相同的。

按照图中所示,我们假设在半径为1的这个球壳上所蕴含的能量为k,而在这个球壳上的每一点的光的强度是I,那么在半径为r的球壳上,在这个球壳上的光线的强度就应该是 I/(rr)。因为根据能量守恒定律,近处的球壳总能量应该与远处的球壳总能量一样,因此我们用近处一点的光照强度 I * 球壳的总面积 4π =远处球壳一点的光照强度 * 4πr^2,我们可以求出远处球壳一点的光照强度就应该是 I/(rr)。

所以这就解释了为什么距离越远,光照的强度越弱。

漫反射的强度计算(Lambertian (Diffuse) Shading)

至此我们知道了光源到shading point处时光的强度大小,我们也知道了shading point会接受多少的能量,我们就可以进行计算了。

假设给定一个点光源,光线的方向向量I,着色点表面的法向量n,观察者的方向向量v,光线的入射角度θ,计算的方法如下:
在这里插入图片描述
在这里插入图片描述

I/(r*r)我们可以求出光源到达shading point时的能量大小,

  • max(0,n 点乘 l )我们可以求出shading point此时接受的能量大小。max(0,)是因为当点乘结果为负数时,我们认为这个结果没有物理意义,因为这种情况是有一条光线从下面穿过物体达到了物体表面。因为我们考虑的是反射,不考虑折射。

为什么会有颜色?
shading point之所以会有颜色,只有一个可能性,那就是shading point吸收了一部分能量,也就是吸收了一部分光,反射出没被吸收的光。

如果不同的点有不同的吸收率,那么得到的结果就会是不同的颜色。
在这里插入图片描述
如果我们定义一个系数kd来表达能量吸收了多少,如果kd=1,则表示这个点完全不吸收,进入的能量 = 出去的能量。如果Kd = 0,那么表示进入的能量全部被吸收。

  • kd是一个系数,代表的是一个物体本身的颜色,或者是材质。因为不同的材质和光线作用的结果不同,所以还要再×这个系数。
    在这里插入图片描述

漫反射的效果,kd从左往右依次增大

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值