games101 实验hw2(作业2)

参考:
【GAMES101】作业2–三角形光栅化
GAMES101作业2-代码框架逐行理解(c++基础巩固)
games101 作业2
GAMES101作业(更新中)
GAMES101作业2及课程总结(重点解决黑边问题)
GAMES101作业2及课程总结(重点解决黑边问题)

题目:

实现以下两个函数:
rasterize_triangle(): 执行三角形栅格化算法
static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。

具体函数分析

bool insideTriangle()

原理

判断点是否在三角形内部:
Games101-lecture02 Linear Algebra
在这里插入图片描述
在这里插入图片描述

代码

分别求AB,AC,BC,AP,BP,CP的向量,然后求叉乘
判断,代码中利用点乘是为了确定方向,点乘>0说明两个向量方向一致

static bool insideTriangle(int x, int y, const Vector3f* _v)
{   
    // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
    Vector3f p(x,y,1.0);
    Vector3f a=_v[0],b=_v[1],c=_v[2];
    Vector3f ab=b-p,ap=p-a,bc=c-b,bp=p-b,ca=a-c,cp=p-c;
    Vector3f ans1=ab.cross(ap),ans2=bc.cross(bp),ans3=ca.cross(cp); 
    if(ans1.dot(ans2)>=0&&ans1.dot(ans3)>=0)
        return 1;
    else 
        return 0;
}

rasterize_triangle()

原理(题目要求pdf中已给出)

具体原理可以看这里
rasterize_triangle(const Triangle& t) 该函数的内部工作流程如下:

  1. 创建三角形的 2 维 bounding box。(需自己实现)
  2. 遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。(判断函数insideTriangle()需要自己实现)
  3. 如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度缓冲区 (depth buffer) 中的相应值进行比较。(注释里已经写好)
  4. 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区 (depth buffer)。(需自己实现)

bounding box:
在这里插入图片描述
深度缓冲的算法(Z-Buffer Algorithm)
在这里插入图片描述

代码:

//Screen space rasterization
float minn(float a,float b,float c){
    return min(a,min(b,c));
}
float maxx(float a,float b,float c){
    return max(a,max(b,c));
}
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();
    
    // TODO : Find out the bounding box of current triangle.
    // iterate through the pixel and find if the current pixel is inside the triangle

    // If so, use the following code to get the interpolated z value.
    //auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
    //float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
    //float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
    //z_interpolated *= w_reciprocal;

    // TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
    
    //1.find bounding box
    int xmin = (int)(minn(v[0].x(),v[1].x(),v[2].x())-0.5);
    int ymin = (int)(minn(v[0].y(),v[1].y(),v[2].y())-0.5);
    int xmax = (int)(maxx(v[0].x(),v[1].x(),v[2].x())+0.5);
    int ymax = (int)(maxx(v[0].y(),v[1].y(),v[2].y())+0.5);
    for(int x=xmin;x<=xmax;x++){
        for(int y=ymin;y<=ymax;y++){
            //2.判断点是否在三角形内部 
            if(insideTriangle(x+0.5,y+0.5,t.v)){
                //3.获取深度值,z_interpolated,利用插值找到每个像素的深度值 
                auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
                float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
                float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
                z_interpolated *= w_reciprocal;
                //4.设置像素颜色并更新深度缓冲区 
                if(z_interpolated < depth_buf[get_index(x,y)]){
                    set_pixel(Vector3f(x,y,z_interpolated),t.getColor());
                    depth_buf[get_index(x,y)] = z_interpolated;
                }
            }
        }
    }

}

效果图:

在这里插入图片描述
仔细看图像边缘会有锯齿感
请添加图片描述
请添加图片描述

请添加图片描述

附加题

用 super-sampling 处理 Anti-aliasing : 你可能会注意到,当我们放大图像时,图像边缘会有锯齿感。我们可以用 super-sampling来解决这个问题,即对每个像素进行 2 * 2 采样,并比较前后的结果 (这里并不需要考虑像素与像素间的样本复用)。需要注意的点有,对于像素内的每一个样本都需要维护它自己的深度值,即每一个像素都需要维护一个 sample list。最后,如果你实现正确的话,你得到的三角形不应该有不正常的黑边。

Anti-aliasing

先模糊,再采样 = 抗走样
在这里插入图片描述

MSAA(Antialiasing By Supersampling)

MSAA是一个对反走样的近似因为按照上面的那种求每个像素中的区域百分比十分困难,所以就有了MSAA这种反走样的方法,其思想也是如上面的那种方法,但是取的是一个近似的求区域像素平均值的方法。
在MSAA中,我们将以划分的每个像素在进行划分,将原有的一个像素分为更多个小像素,这跟题目要求是一致的(对每个像素进行 2 * 2 采样)
在这里插入图片描述
具体步骤:
1.将原有的一个大像素分为四个小像素,每个点都可以判断是否在三角形内,如果四个点都在三角形内就是100%覆盖,也就是100%的红色,如果只有三个点在三角形内,则三角形对这个像素就是75%覆盖,其颜色也就是75%的红色+25%的白色。于是就可以得出每个像素的覆盖结果。就相当于模糊做完了
2.然后再采样,这时采样就会十分简单,因为我们规定像素是最小的单位格子,每个格子的颜色都是平均的(像素内的颜色都是一样的),采样完也就会得到上图的结果。

代码实现

参考:
每个像素拆分成四个小像素,分别记录其深度和颜色,该大像素是这四个小像素颜色的平均值,然后再进行着色(比如在交叉线上,可能绿色占四分之一,蓝色占四分之三)

效果图

在这里插入图片描述

注意:

1.hw1中z轴是负的,而hw2中题目将z轴进行了处理,报保证为正数
在这里插入图片描述

因此在引用hw1中写的get_projection_matrix时,这里的abs要改成-1*zNear的写法,不然图像会反转过来(因为z已经是正的了,abs(z)不会有任何影响,而在hw1中z是负数,所以-1和abs效果是一样的)
在这里插入图片描述
在这里插入图片描述

### Games101 作业2 拓展资料与解决方案 #### 关于Bounding Box的应用 在计算机图形学中,bounding box用于定义物体的空间边界。对于复杂的几何形状,通过创建包围这些对象的简单矩形体来简化碰撞检测和其他交互操作[^1]。 #### 纹理映射中的挑战 当处理低分辨率纹理贴图应用于高分辨率显示器时,可能会遇到图像失真问题。具体来说,如果原始纹理尺寸较小而目标显示区域较大,则单个纹素可能映射到多个屏幕像素上,从而造成视觉上的不连续性和锯齿效应[^2]。解决这一问题的方法之一是对纹理应用过滤算法,如双线性插值或三线性滤波,以平滑过渡效果。 #### 文件管理的安全实践 为了维护系统的安全性,在多用户环境下应当谨慎对待文件管理和权限设置。例如,在Linux系统中移除不再活跃用户的账户及其关联的数据之前,应该先清理其个人目录下的所有内容,防止敏感信息泄露给新使用者[^3]。 #### 光照模型的选择依据 根据不同材质属性选择合适的光照计算方法至关重要。漫反射(diffuse)通常只需较低阶数就能获得满意的效果;而对于镜面反射(glossy),则往往需要更高阶次才能精确模拟真实世界物理现象,并且随着精度提升会带来额外性能开销和内存占用增加的问题[^4]。 #### 开发环境搭建指南 针对C++项目开发,采用现代工具链能够显著提高工作效率。利用`make`命令可以方便地编译源码以及清理临时生成物;借助`CMake`框架不仅有助于跨平台支持还便于集成第三方库(像Eigen这样的数学运算库)。此外,配置好IDE(例如VSCode)能进一步增强编码体验[^5]。 ```cpp // 示例:简单的C++程序结构 #include <iostream> int main() { std::cout << "Hello, GAMES101!" << std::endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值