🗒️GAMES101 作业3

type
status
date
slug
summary
tags
category
icon
password
😀
学习过程中的输出和应用很重要,还是得坚持写写博客,才能把知识消化吸收,也有助于养成好的学习习惯。
本次的作业内容主要为完成不同的Shader,加深对一些光照计算的理解。

准备工作

在一切开始之前,需要一些准备工作。
由于 Mac 和 Windows 屏幕坐标的起点不同,我们需要稍微变换一下透视投影矩阵。
具体如下:
在透视投影的最后一步,我们需要与正交投影矩阵相乘。
由于坐标起点不同,直接变换方向即可。
有些读者会有疑惑,这样做是否对后续的计算产生影响?
不用着急,后续在讲述插值的时候,我会作出详细的说明。

三角形的插值

首先,我们需要对非顶点的 Shading Point 进行属性的插值。
通常来讲,图元的属性存储在顶点上,对于中间的着色点,我们需要有一种方法来获得其着色相关的属性,包括但不限于:
  1. 颜色
  1. 法线
  1. Shading Point(该着色点的世界坐标)
  1. 纹理坐标(u,v)
而对三角形而言,我们使用的方法是重心坐标插值
作业的代码框架中,给出了插值的 helper 函数:
该函数的输入是该点的重心坐标,以及三角形三个顶点的属性值。
weight 的作用是进行透视修正。
简单来说,在透视投影后,三角形的重心坐标会发生变化。
为了修正这种变化,我们通常利用深度值进行透视投影的修正。
透视投影
透视投影
如图所示,投影后的 ab 的中点 c,在世界空间当中(或者说视锥体当中)对应的点并不是中点。
在本次作业中,除了深度(z)需要修正,其他数值 Yan 并不需要我们去完成属性插值的透视修正。也就是我们只需要对三角形进行简单的插值即可,不需要考虑透视带来的误差。
因此,在这里我不展开介绍透视修正的具体推导和公式,感兴趣的读者可以自行学习。

深度插值

首先,我们需要对深度进行插值,保证 z-buffer 算法能够正确的计算。
因为深度上的误差会对图形渲染产生巨大的影响,所以我们对其进行了透视修正,具体的代码如下。
值得注意的是,这里的重心坐标(即alpha, beta, gamma)是在屏幕空间中的三角形重心坐标。
也就是说,我们在计算三角形的重心坐标时,已经完成了投影变化,这点需要我们特殊注意。
具体依赖的公式如下:
需要注意的是,公式的 Z 代表该着色点世界空间中的深度,而非透视投影后的深度。
💡
回忆在 View 变换章节中,我们对 z 的处理既保留了相对的大小关系,又能通过逆变换找到原来的 z 数值

其他属性插值

其他属性不进行投影修正(我尝试过进行投影修正,得到的结果和答案不同),因此我们将 weight 设置为 1,代表不进行修正。
最后,将插值得到的属性封装到结构体,送给 Shader 进行计算。
在插值完成之后,我们可以查看相应的法线插值结果,运行命令:
我们可以得到得到结果:
normal shader
normal shader

关于变换

前文提到,为了得到和答案一样的结果,我对透视投影当中的正交变换矩阵进行了修正。
那么这种修正是否会影响到着色的计算?
我们计算的时候使用的是三角形的重心坐标进行计算,因此,修改透视变换矩阵不会对其后续的计算产生影响(着色点的重心坐标没有发生改变)。
可以想象:将三角形任意旋转,着色点相对三个顶点的位置仍然不变,整个过程类似线性代数的基变换。

Blinn-Phong Shader

接下来,我们需要实现 Blinn-Phong 着色模型。
在代码框架当中,我们需要实现 phong_fragment_shader 函数。
我们需要计算各个部分的光照,将其累加到像素的颜色值上,光照部分包括:
  1. 环境光
  1. 漫反射光
  1. 高光
其中,漫反射光和高光是每个光源都需要进行计算,而环境光则单独计算一次即可。
在这里,环境光被简单处理,我们直接为每个像素添加一定的颜色即可。
具体的代码如下:
其中,需要注意的是,光线本身也有颜色(或者说强度)。
反映在单个着色点上,光的强度和距离的平方呈反比。
此外,我们需要使用的是逐元素的乘法,而非矩阵乘法,因此需要使用 cwiseProduct 。默认的 * 符号重载的是矩阵乘法,需要注意。
在计算高光的时候,我使用半程向量来避免负数的判断。
具体的计算公式这里不列出,参考 Yan 的课件或者虎书就好。
得到的结果如下:
phong shader
phong shader

Texture Shader

接下来,我们需要为图形添加纹理。
在代码框架中,我们需要完善 texture_fragment_shader 函数。
我们仅仅需要添加纹理映射的代码即可,而纹理坐标的插值,我们在前面的过程中已经完成。
其本质就是给当前着色点一个具体的颜色,代码如下
在光照渲染环节,我们直接沿用 phong shader 的代码即可,节约篇幅,这里不再复制。
得到结果:
phong shader
phong shader
一只可爱的小奶牛就渲染完成了。

Bump Shader(凹凸贴图)

凹凸着色,通过对法线进行偏离来让着色效果更佳真实。
将 Texture 映射为高度,以此来扰动法线。
需要注意,凹凸贴图没有实际的更改着色点的位置,仅仅是通过修改表面的颜色来达到类似的效果,欺骗人的眼睛。
代码框架中给出了实现的大致逻辑,照着实现就好。
代码上方是框架给出的实现逻辑,这里保留,方便读者对比。
得到结果:
bump shader
bump shader
确实多了凹凸不平的纹理效果。

Displacement Shader(位移贴图)

利用 bump shader 计算的法线和 phong shader 光照计算结合。
此外,我们需要真实的移动着色位置,只需要在着色时添加一行代码:
改变实际的着色点的位置(沿着法线移动)。
得到结果:
displacement shader
displacement shader

📎 参考文章

  • Games 101
  • 虎书
上一篇
游戏求职之路
下一篇
渲染管线(Pipeline)
Loading...