games101作业2解题办法详解

作业2的整体代码框架和作业1相同,不同点在于这次需要绘制的是实心的三角形,且两个三角形之间有重叠,所以需要做深度检测。
这是此次作业的要求。
在这里插入图片描述
首先来实现三角形的栅格化算法函数 rasterize_triangle(const Triangle& t)
在给定的作业要求pdf中已经给了具体的算法,我们只需要将算法转换成代码即可。

1、首先需要建立三角形的bounding box,这个box就是一个二维的矩形,是可以把三角形包围起来的最小矩形

    auto v = t.toVector4();//三角形的三个顶点,是一个包含三个Vector4f的array
    Eigen::Vector2f minpoint, maxpoint;//创建的二维bounding box
    minpoint.x() = MIN(MIN(v[0].x(), v[1].x()), v[2].x());
    minpoint.y() = MIN(MIN(v[0].y(), v[1].y()), v[2].y());
    maxpoint.x() = MAX(MAX(v[0].x(), v[1].x()), v[2].x());
    maxpoint.y() = MAX(MAX(v[0].y(), v[1].y()), v[2].y());

这里我创建了两个vector来储存这个box的大小,代码不难,不做讲解。只有得到了这个box,接下来我们才能判断box里的点是否在三角形里面,实际上不要这个box也可以,直接对整个显示屏幕进行采样,但是这样会大大浪费掉计算机的性能,没必要。

2、遍历box里的所以像素点,这里使用整数索引即可。判断这些像素点是否在三角形内部

for (int i = minpoint.x(); i < maxpoint.x(); ++i)

        for (int j = minpoint.y(); j < maxpoint.y(); ++j)
        	if (insideTriangle(x, y, vec))//在三角形里面

如果在三角形内部,那就需要计算出深度值,这里老师直接给了计算方法

std::tuple<float, float, float> temp =computeBarycentric2D(i, j, t.v);
float alpha = std::get<0>(temp);
float beta = std::get<1>(temp);
float gamma = std::get<2>(temp);
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;

关于computeBarycentric2D()

static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
{
    float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());
    float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());
    float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());
    return {c1,c2,c3};
}

忘了说判断像素点是不是在三角形里面的算法insideTriangle()

static bool insideTriangle(float x, float 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]
    Eigen::Vector3f point = { x,y,0 };
    Eigen::Vector3f vec0 = _v[1] - _v[0];//三条边向量
    Eigen::Vector3f vec1 = _v[2] - _v[1];
    Eigen::Vector3f vec2 = _v[0] - _v[2];

    float a = ((point - _v[0]).cross(vec0)).z();//做叉积
    float b = ((point - _v[1]).cross(vec1)).z();
    float c = ((point - _v[2]).cross(vec2)).z();


    if ((a > 0 && b > 0 && c > 0)||(a < 0 && b < 0 && c < 0))
    {
        //std::cout << "a:" << a << "  b:" << b << "  c:" << c << std::endl;
        return true;//在三角形里面
    }
    else
    {
        return false;//不在
    }
}

算法很简单,老师在上课的适合也说过,就是做叉积。
最后判断像素点的depth深度,比较和深度缓冲区里储存的数值的大小,要是更小,就更新深度缓冲区。
提高作业:
提高作业的要求是使用SSAA算法反走样,抗锯齿,就是改变一下rasterize_triangle()函数里面的部分代码,这里只贴主要的代码

if (insideTriangle(x, y, vec))//在三角形里面
                    {
                        std::tuple<float, float, float> temp = computeBarycentric2D(i, j, t.v);
                        float alpha = std::get<0>(temp);
                        float beta = std::get<1>(temp);
                        float gamma = std::get<2>(temp);
                        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;
                        depth = MIN(depth, z_interpolated);
                        color = color + t.getColor();
                        flag++;

                    }
                }
                if (flag > 0)//有像素点在三角形里面
                {
                    if (depth < depth_buf[(get_index(i, j))])//离摄像机更近
                    {
                        set_pixel(Eigen::Vector3f(i, j, 1), color / 4.0);
                        depth_buf[get_index(i, j)] = depth;
                    }
                }
            }

其实SSAA算法就是找更多的检测点而已,把一个整数像素点又分为四个小的监测点,这样得到的四个点的color的平均值来对此像素着色,可以达到模糊边界,也就是抗锯齿的效果。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值