目录
第一题
题目: 判断给定的点(x, y)是否在三角形内
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]
}
解析:
这里要注意的一点就是 x 和 y 坐标都需要加 0.5, 这样才能将将坐标偏移到像素中心(关于这点闫老师在课中提过), 不过测试时加不加 0.5 看不出差别。
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]
x += 0.5; //像素中心的 x 坐标
y += 0.5; //像素中心的 y 坐标
Eigen::Vector3f pt(x, y, 0);
std::vector<Vector3f> vertexs;
for (int i = 0; i < _v->size(); ++i)
{
Eigen::Vector3f temp(_v[i].x(), _v[i].y(), _v[i].z());
vertexs.emplace_back(temp);
}
for (int i = 0; i < vertexs.size(); ++i)
{
int next = i == (vertexs.size() - 1) ? 0 : i + 1;
Eigen::Vector3f ans = (pt - vertexs[i]).cross(vertexs[next] - vertexs[i]);
if (ans.z() > 0) //如果叉乘后 z 大于0, 则证明点在向量的右侧,此时直接返回 false
{
return false;
}
}
return true;
}
第二题
题目: 找到给定三角形的最大包围盒并遍历其中的点, 如果这个点在三角形内, 则使用重心插值算法计算出该点的深度(在 shading 课程中会提到重心插值计算), 当点的深度小于深度缓存中的值时进行着色。
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.
}
解析:
值得注意的一点就是一定要记得着色后更新深度缓存(depth_buf)中对应的值。
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
//以下四行计算三角形包围盒点的边界
float x_max = max(max(v[0].x(), v[1].x()), v[2].x());
float y_max = max(max(v[0].y(), v[1].y()), v[2].y());
float x_min = min(min(v[0].x(), v[1].x()), v[2].x());
float y_min = min(min(v[0].y(), v[1].y()), v[2].y());
// 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.
//开始遍历包围盒中的所有点
for (int i = x_min; i < x_max + 1; ++i)
{
for (int j = y_min; j < y_max + 1; ++j)
{
if (insideTriangle(i, j, t.v)) //如果该点在三角形中, 则开始计算其深度
{
auto [alpha, beta, gamma] = computeBarycentric2D(i, j, 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 (depth_buf[get_index(i, j)] > z_interpolated) //获取当前点在深度缓存中的值, 如果大于插值计算出的 z 值, 则上色
{
Vector3f temp(i, j, 1);
set_pixel(temp, t.getColor()); //着色
depth_buf[get_index(i, j)] = z_interpolated; //不要忘记更新深度缓存
}
}
}
}
}