GAMES101 作业记录

作业1

  • 模型变换矩阵实现绕轴旋转
    绕某一轴旋转的矩阵:
    R_x(\alpha)=\begin{pmatrix}1&0&0&0\\0&cos\alpha&-sin\alpha&0\\0&sin\alpha&cos\alpha&0\\0&0&0&1\end{pmatrix},R_y(\alpha)=\begin{pmatrix}cos\alpha&0&sin\alpha&0\\0&1&0&0\\-sin\alpha&0&cos\alpha&0\\0&0&0&1\end{pmatrix},R_z(\alpha)=\begin{pmatrix}cos\alpha&-sin\alpha&0&0\\sin\alpha&cos\alpha&0&0\\0&0&1&0\\0&0&0&1\end{pmatrix}
    绕任意轴旋转的矩阵:
  • 透视投影变换矩阵
    透视变换:将由定义的视锥体(frustum)转换成标准坐标空间(Normalized device Coordinaate)中的规则观察体(Canonical View Volume)。
    M_{ortho}=\begin{pmatrix}\frac{2}{r-l}&0&0&\frac{r+l}{l-r}\\0&\frac{2}{t-b}&0&\frac{t+b}{b-t}\\0&0&\frac{2}{n-f}&\frac{n+f}{f-n}\\0&0&0&1\end{pmatrix},M_{persp}=\begin{pmatrix}n&0&0&0\\0&n&0&0\\0&0&n+f&-nf\\0&0&1&0\end{pmatrix}

    其中分别为透视变换后的观察体的右面、左面、上面和下面。

作业2

  • 三角形内部测试
    给定三角形,求出三角形所在的轴对齐包围盒(Axis Aligned Bounding Box,AABB),遍历AABB内的像素,测试像素在不在三角形内。
    三角形内部测试方法:
  1. 计算PAxPB PBxPC PCxPA同号
  2. 计算重心坐标u v,u和v分别在[0,1]内
  3. 点P点A在直线BC同侧 && 点P点B在直线AC同侧 && 点P点C在直线AB同侧
  4. RTR4中介绍的:硬件对于三角形的每一个边都计算该边的边缘函数,代表在边缘内侧,代表在边缘外侧,代表在边缘上。对三条边都计算边缘函数,如果都满足,则表示在三角形内。

    上式表述了三角形中,边的边缘函数。其中,为测试点,可以为边上任意一点(这里取了边上顶点),为边上的法向量(我们通过边上的顶点和来得到边的向量,将逆时针旋转90°得到边法向量)

注意:参与测试的像素要选取像素中心,也就是第个像素坐标为。

  • 深度插值与Z-buffer
    对于通过了内部测试的像素,要通过重心坐标对其进行深度插值
    需要注意的是:作业框架在此给出了提示,框架这里是将深度插值和透视除法一起计算的,由于进行了透视除法,所以插值后做了透视校正。最终得到插值后的该像素的深度。
 // 计算重心坐标
auto [a, b, c] = computeBarycentric2D((float)i+0.5, (float)j+0.5, t.v);
// 深度插值和透视除法
float z_interpolated = a* v[0].z() / v[0].w() + b * v[1].z() / v[1].w() + c * v[2].z() / v[2].w();
// 透视校正
float w_reciprocal = 1.0/(a / v[0].w() + b / v[1].w() + c / v[2].w());
z_interpolated *= w_reciprocal;

然后比对该像素深度与Z-buffer中该像素的深度(深度测试),如果目前深度比Z-buffer中该像素的深度更小(也就是离相机更近),则更新Z-buffer中该像素深度。

  • 光栅化
    通过了深度测试的像素,插值出颜色,写入到framebuffer中,完成光栅化。

  • SSAA
    SSAA在每像素使用N个采样点来代替单个像素中心,都做一次着色,然后将像素内的多个采样点降采样成一个像素,实现超采样的效果。在这里的SSAA中,我简化了过程,把每个采样点当作前文中的像素中心,在每个像素点中,都遍历每个采样点进行内部测试、深度插值(不做深度测试和着色了,记录采样点的个数在像素内只着色一次,这种行为更像是MSAA)。记录每个像素中通过内部测试的采样点个数,在光栅化该像素时,将像素颜色与framebuffer中原本的颜色,根据采样点比例做线性插值,达到柔和边缘的效果。

if(minDepth

采样点的位置选取也有讲究,不会在像素内均匀分布采样点,而是使用低差异采样序列,比如RGSS、Halton 序列、Poisson disk等。

作业3

  • 参数插值
    调用给定的插值函数对属性插值即可。

  • Blinn-Phong模型的实现
    Blinn-Phong着色模型考虑了物体的材质性质、光源的性质、入射光和出射光,所以需要在着色点对于所有的光源遍历。Blinn-Phong模型将物体着色考虑为固定数值环境光()+漫反射()+镜面反射(),是比较简单的着色模型。公式为:

    其中,分别为表面的环境光系数、漫反射系数和镜面反射系数。分别为光源的环境光、漫反射和镜面反射项。分别为表面法线、入射光线和半程向量。为高光项,控制高光亮度和范围。
    Phong与Blinn-Phong的区别:高光项上,phong是计算视线与反射光线方向夹角,blinn-phong是计算法线与半程向量夹角。phong夹角过大时取0,导致blinn-phong高光范围更大

  • 纹理映射
    与Blinn-Phong模型相似,不同之处在于,采样纹理得到的纹理颜色值需要作为表面的漫反射项参与到Blinn-Phong模型的着色中。

  • 凹凸贴图与位移贴图
    凹凸贴图和法线贴图本质上是一样的,凹凸贴图定义了位置的法线差异,而法线贴图直接定义了法线,二者是可以互相计算出来的。这里有几个注意问题:

  1. 作业里做凹凸贴图使用的是法线图,注意作业里的法线贴图是将纹理的作为了切线空间的法线的差异,从而求得方向的增量和方向的增量,变换后的切线空间的法线就是,所以将切线空间的法线通过TBN矩阵转换回世界空间,就获得了世界空间的变换后的法线。
  2. 由于作业中法线贴图保存的是法线的移动距离,所以在计算位移时,就是位移的移动量,将顶点坐标沿法线方向移动后,就是位移后的顶点位置。
  3. 作业中计算TBN矩阵的方式只用到了着色点的法线,不需要其他信息,这是一种巧妙的方式,但不完善,正确的做法应该求三角形边缘向量映射到纹理空间中的转换。即:

    ,,,
    其中,三角形上三个顶点为,对应的纹理坐标为。
  • 双线性插值采样纹理
    找到采样点周围的4个像素,对这4个像素根据采样点的位置两两横向插值一次,再将得到的插值结果根据采样点的位置纵向插值,得到双线性插值后的结果。

作业5

Whitted风格的光线追踪:从每个着色像素发射光线,光线到达光滑物体发生反射和折射,并继续追踪反射和折射光线;当光线到达漫反射物体时,对每个光源都计算Phong着色,终止光线追踪。
由于场景中物体较少,所以没有使用加速结构,每次追踪光线都遍历所有场景内的物体,判断与光线的相交。

  • 光线生成
    光线追踪将摄像机看作一个针孔摄像机,而需要渲染的像素就是底片,但是我们不将底片放在摄像机镜头后(因为小孔成像会倒置),而是放在镜头前避免倒置。通常将底片放在镜头前方距离为1(世界空间)的位置。所以生成光线的过程,就是在世界空间中摆放底片,并通过摄像机和像素位置生成光线的过程。
    我们需要将屏幕光栅空间的像素位置,转换回世界空间(摄像机空间),并摆放在摄像机前方1单位的位置上,得到像素在世界空间的虚拟位置,连接摄像机和像素的光线,就是要生成和追踪的光线。
    具体操作:Ray-Tracing: Generating Camera Rays (Generating Camera Rays)

  • 光线和三角形求交
    Moller Trumbore算法:简单来说,Moller Trumbore算法通过光线起始、光线方向和三角形三个顶点,计算光线传播时间和重心坐标的方法。最终,如果、、和均不小于0,则判定为相交。

    MollerTrumbore.png

作业6

  • 光线与包围盒求交
    方法:分别求光线与6个面的交点值。然后可知光线与整个AABB的出入的值——,(光线和三对面都有交点了,光线才算是进入到AABB中,所以进入时间是进入三对面时最大的;只要再和另一个面相交,光线就离开AABB了,所以离开时间是光线和三对面中另一侧相交最小的)。如果说明光线在AABB中逗留了一段时间,也就是和AABB有交点。反之则没有交点。
    所以,光线和AABB有交点的条件是:(光源在AABB内部也算)。
    注意:这里在源码的Bounds3::IntersectP函数中,有一个std::array& dirIsNeg参数,用来判断光线相交的方向是否与传播方向相反,如果相反则要将相应的对平面的进出时间对换。

  • 光线与BVH相交的查找
    由于物体只保存在BVH的叶节点上,所以我们需要一直查找到直到到达BVH树的叶节点上。
    遍历的过程就是二叉树的中序遍历,在叶节点出调用物体与光线求交的方法。

作业7

  • Path Tracing
    Path Tracing简单来说是用蒙特卡洛方法求解渲染方程。对于每条光路的着色结果,需要计算这条光路接触到的表面的直接光照和间接光照。直接光照需要直接采样面光源并考虑遮挡,间接光照需要随机采样一条出射光路,计算再次接触到的表面作为次级光源对着色表面的贡献。间接光照的采样添加俄罗斯轮盘赌的方法,限制光路弹射次数的同时,理论上做到不损失能量(所以不需要定义光线最深弹射次数)。每个像素发射多条光路(sample per pixel,spp),将多条光路的着色效果加权平均作为该像素的最终着色结果。
    由于实现假设了所有的表面均是diffuse的,所以每次弹射的pdf可以认为是在法线半球均匀分布的。

你可能感兴趣的:(GAMES101 作业记录)