games101 第二次作业 反走样与Zbuffer

1 总览
在上次作业中,虽然我们在屏幕上画出一个线框三角形,但这看起来并不是
那么的有趣。所以这一次我们继续推进一步——在屏幕上画出一个实心三角形,
换言之,栅格化一个三角形。上一次作业中,在视口变化之后,我们调用了函数
rasterize_wireframe(const Triangle& t)。但这一次,你需要自己填写并调用
函数 rasterize_triangle(const Triangle& t)。
该函数的内部工作流程如下:
1. 创建三角形的 2 维 bounding box。
2. 遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中
心的屏幕空间坐标来检查中心点是否在三角形内。
3. 如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度
缓冲区 (depth buffer) 中的相应值进行比较。
4. 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区 (depth buffer)。
你需要修改的函数如下:
• rasterize_triangle(): 执行三角形栅格化算法
• static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函
数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。
因为我们只知道三角形三个顶点处的深度值,所以对于三角形内部的像素,
我们需要用插值的方法得到其深度值。我们已经为你处理好了这一部分,因为有
关这方面的内容尚未在课程中涉及。插值的深度值被储存在变量 z_interpolated
中。
 
请注意我们是如何初始化 depth buffer 和注意 z values 的符号。为了方便
同学们写代码,我们将 z 进行了反转,保证都是正数,并且越大表示离视点越远。
 
实现如下:
我也实现了MSAA
第一次做的时候好像求最大最小值那里出了一点问题,现在没有问题了
 
 
代码实现如下:

static bool insideTriangle(float x, float y, const Vector3f* _v)
{   
    Eigen::Vector3f P(x,y,0);
    Eigen::Vector3f AB(_v[1].x()-_v[0].x(),_v[1].y()-_v[0].y(),0);
    Eigen::Vector3f BC(_v[2].x()-_v[1].x(),_v[2].y()-_v[1].y(),0);
    Eigen::Vector3f CA(_v[0].x()-_v[2].x(),_v[0].y()-_v[2].y(),0);
    Eigen::Vector3f AP(x-_v[0].x(),y-_v[0].y(),0);
    Eigen::Vector3f BP(x-_v[1].x(),y-_v[1].y(),0);
    Eigen::Vector3f CP(x-_v[2].x(),y-_v[2].y(),0);
    Eigen::Vector3f ABxAP = AB.cross(AP);
    Eigen::Vector3f BCxBP = BC.cross(BP);
    Eigen::Vector3f CAxCP = CA.cross(CP);
    if(ABxAP.dot(BCxBP)>0&&CAxCP.dot(BCxBP)>0)
    {
        return true;
    }
    return false;
    // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
}

 

然后是MSAA和Zbuffer的实现

 

注意,我们利用getindex函数得到具体的某个光栅里面的值,然后进行Zbuffer比较

其中我们实现了MSAA,注意,是四个点,而且一个pixel中的像素的最小值这里我们按这四个子像素中的最小值进行计算(我们这里,Z值取绝对值)

 

void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();
    float min_x = std::min(v[0][0], std::min(v[1][0], v[2][0]));
    float max_x = std::max(v[0][0], std::max(v[1][0], v[2][0]));
    float min_y = std::min(v[0][1], std::min(v[1][1], v[2][1]));
    float max_y = std::max(v[0][1], std::max(v[1][1], v[2][1]));

    min_x = (int)std::floor(min_x);
    max_x = (int)std::ceil(max_x);
    min_y = (int)std::floor(min_y);
    max_y = (int)std::ceil(max_y);
    std::vector<Eigen::Vector2f> pos
        {
            {0.25,0.25},
            {0.75,0.25},
            {0.25,0.75},
            {0.75,0.75},
        };
    //MSAA program
   for (float x = min_x; x <= max_x; x++) {
            for (float y = min_y; y <= max_y; y++) {
             // 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.
            int count = 0;
            float minDepth = FLT_MAX;
            for(int i=0;i<=3;i++)
            {
                
            if(insideTriangle(x+pos[i][0],y+pos[i][1],t.v))
            {  
                count++;
                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;
                minDepth = std::min(minDepth, z_interpolated);
            }
            }
                Eigen::Vector3f color = t.getColor()*count/4;
                int zindex = get_index(x,y);
                Eigen::Vector3f tmp(x,y,minDepth);
                
                if(depth_buf[zindex]>minDepth)
                {
                   
                    set_pixel(tmp,color);
                    depth_buf[zindex] = minDepth;
                }
}

最后效果如下:

posted @ 2021-01-23 20:06  coolwx  阅读(500)  评论(0编辑  收藏  举报