Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
Eigen::Matrix4f persp_matrix;//透视矩阵
Eigen::Matrix4f translate_matrix;//移动矩阵
Eigen::Matrix4f scale_matirx;//缩放矩阵
persp_matrix << zNear, 0, 0, 0,
0, zNear, 0, 0,
0, 0, zNear + zFar, -zNear * zFar,
0, 0, 1, 0;
float halfAngle = eye_fov / 2 / 180 * MY_PI;
float height = -2 * std::tan(halfAngle) * zNear;//没有负号则三角形上下颠倒
float width = height * aspect_ratio;
translate_matrix << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, -(zNear + zFar) / 2,
0, 0, 0, 1;
scale_matirx << 2 / width, 0, 0, 0,
0, 2 / height, 0, 0,
0, 0, 2 / (zNear - zFar), 0,
0, 0, 0, 1;
projection = scale_matirx * translate_matrix * persp_matrix;
return projection;
}
函数在rasterizer.cpp中
测试点是否在三角形内
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
bool sign[3];//记录三角形边向量和测试点顶点向量叉乘符号
for(int i = 0; i < 3; i++){
Vector3f vec1(x - _v[i].x(), y - _v[i].y(), 1);//测试点顶点向量
Vector3f vec2(_v[(i + 1) % 3].x() - _v[i].x(), _v[(i + 1) % 3].y() - _v[i].y(), 1);//边向量
sign[i] = vec1.cross(vec2).z() > 0;
}
if(sign[0] == sign[1] && sign[0] == sign[2]) return true;//符号相同,则在三角形内
return false;
}
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;
//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
// TODO : Find out the bounding box of current triangle.
int bounding_box_x_left = std::min(v[0].x(), std::min(v[1].x(), v[2].x()));
int bounding_box_x_right = std::max(v[0].x(), std::max(v[1].x(), v[2].x()));
int bounding_box_y_left = std::min(v[0].y(), std::min(v[1].y(), v[2].y()));
int bounding_box_y_right = std::max(v[0].y(), std::max(v[1].y(), v[2].y()));
// iterate through the pixel and find if the current pixel is inside the triangle
for(int x = bounding_box_x_left; x <= bounding_box_x_right; x++){
for(int y = bounding_box_y_left; y <= bounding_box_y_right; y++){
if(insideTriangle(x, y, t.v)){//如果该点在三角形内,则需要光栅化
// 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.
if(z_interpolated < depth_buf[get_index(x, y)]){//z保证都是正数,并且越大表示离视点越远
// 如果(x,y)离视点近,则需要重新绘制
depth_buf[get_index(x, y)] = z_interpolated;
set_pixel(Eigen::Vector3f(x, y, z_interpolated), t.getColor());
}
}
}
}
}