作业2的内容包含两个部分:
1、完成三角形栅格化算法
2、编写函数insideTriangel,用于在栅格化的时候判断某一点是否在三角形内
insideTriangel
如何判断某一点与三角形的内外关系,使用到的方法是叉乘,将三角形的三个顶点顺序相连形成三个有序的向量AB,BC,CA,分别与向量AP,BP,CP相乘,如果符号相同,则P在三角形内,否者在三角形外。
实现代码如下
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]
Eigen::Vector3f p(x, y, 1);
Eigen::Vector3f ab = _v[1] - _v[0];
Eigen::Vector3f bc = _v[2] - _v[1];
Eigen::Vector3f ca = _v[0] - _v[2];
Eigen::Vector3f ap = p - _v[0];
Eigen::Vector3f bp = p - _v[1];
Eigen::Vector3f cp = p - _v[2];
if (ab.cross(ap).dot(bc.cross(bp)) > 0 &&
ab.cross(ap).dot(ca.cross(cp)) > 0) {
return true;
}
else {
return false;
}
}
三角形栅格化
代码框架的注释中其实给出了具体的思路
1、获取三角形的包围盒,用于减少计算量,不至于遍历屏幕上的每一个点
// TODO : Find out the bounding box of current triangle.
float Xmin = INT_MAX;
float Xmax = INT_MIN;
float Ymin = INT_MAX;
float Ymax = INT_MIN;
for (auto v : t.v) {
Xmin = std::min(Xmin, v.x());
Xmax = std::max(Xmax, v.x());
Ymin = std::min(Ymin, v.y());
Ymax = std::max(Ymax, v.y());
}
2、遍历包围盒中的每一个像素,并且判断是否在三角形内部
这一步用到了insideTriangle函数,注意的是并不是针对x,y坐标计算是否在三角形内,而是计算每个像素中心是否在三角形内部,所以是x+0.5,y+0.5
for (int x = Xmin; x <= Xmax; x++) {
for (int y = Ymin; y <= Ymax; y++) {
if (insideTriangle(x + 0.5, y + 0.5, t.v)) {
float alpha, beta, gamma;
std::tie(alpha, beta, gamma) = computeBarycentric2D(x+0.5, y+0.5, 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;
if (z_interpolated < depth_buf[get_index(x, y)]) {
depth_buf[get_index(x, y)] = z_interpolated;
set_pixel(Vector3f(x, y, 1), t.getColor());
}
}
}
}
第二个if语句实现了z-buffer深度缓存,判断当前点的z值是否小于buffer中存储的值,只有当该z值小于buffer中的值时,才会将该点显示在屏幕上,并且更新z-buffer
运行结果
三角形上下颠倒的原因可能是框架中使用的时左手系,所以与作业1的结果不太一样。