任务
- 判断二维空间中,点是否在三角形内
- 深度缓冲的z-buffer算法
- 超采样
任务1
课件中给出了一个算法用来判断点是否在三角形内,即判断点p始终在逆时针存储的三角形ABC的AB、BC、CA的有向边的左手边。这里计算的时候由于不知道三角形是顺时针存储还是逆时针存储,只要p始终在有向边的一边,我就判断p在三角形内部。
另外,这里用三维的叉乘也可以,不过最终都回到判断z方向的正负号的问题上来,所以二维三维都可以。
float cross_2d(Eigen::Vector2f v, Eigen::Vector2f w){
return v.x()*w.y()-v.y()*w.x();
}
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]
float x_p = x;
float y_p = y;
Eigen::Vector2f AB(_v[1].x() - _v[0].x(),_v[1].y()-_v[0].y());
Eigen::Vector2f BC(_v[2].x() - _v[1].x(),_v[2].y()-_v[1].y());
Eigen::Vector2f CA(_v[0].x() - _v[2].x(),_v[0].y()-_v[2].y());
Eigen::Vector2f AP(x_p - _v[0].x(),y_p-_v[0].y());
Eigen::Vector2f BP(x_p - _v[1].x(),y_p-_v[1].y());
Eigen::Vector2f CP(x_p - _v[2].x(),y_p-_v[2].y());
if(cross_2d(AB,AP)*cross_2d(BC,BP)>=0&&cross_2d(AB,AP)*cross_2d(CA,CP)>=0)return true;
else return false;
}
任务2
由于中心插值已经写好了,所以只写了一个画家算法,非常简单的判断。
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
int max_x = std::max(std::max(v[0].x(),v[1].x()),v[2].x());
int min_x = std::min(std::min(v[0].x(),v[1].x()),v[2].x());
int max_y = std::max(std::max(v[0].y(),v[1].y()),v[2].y());
int min_y = std::min(std::min(v[0].y(),v[1].y()),v[2].y());
for(int x = min_x;x<=max_x;x++){
for(int y = min_y;y<=max_y;y++){
// std::cout << x << " " << y << std::endl;
if(insideTriangle(x + 0.5,y + 0.5,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;
// std::cout << z_interpolated << std::endl;
if(z_interpolated < depth_buf[get_index(x,y)]){
depth_buf[get_index(x,y)] = z_interpolated;
set_pixel(Vector3f(x,y,0),t.getColor());
// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}
}
}
}
}
任务3
MSAA超采样,额外存储了一个4倍的深度缓冲,在深度测试时有四倍的计算量。但在算shader的时候没有增加计算量?
void rst::rasterizer::rasterize_triangle_MSAA(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
int max_x = std::max(std::max(v[0].x(),v[1].x()),v[2].x());
int min_x = std::min(std::min(v[0].x(),v[1].x()),v[2].x());
int max_y = std::max(std::max(v[0].y(),v[1].y()),v[2].y());
int min_y = std::min(std::min(v[0].y(),v[1].y()),v[2].y());
std::vector<float> x_offset = {0.25,0.25,0.75,0.75};
std::vector<float> y_offset = {0.25,0.75,0.25,0.75};
for(int x = min_x;x<=max_x;x++){
for(int y = min_y;y<=max_y;y++){
// std::cout << x << " " << y << std::endl;
for(int i = 0;i<4;i++){
float x_f = x + x_offset[i];
float y_f = y + y_offset[i];
int ind = get_index(x,y);
if(insideTriangle(x_f,y_f,t.v)){
// If so, use the following code to get the interpolated z value.
auto[alpha, beta, gamma] = computeBarycentric2D(x_f, y_f, 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;
// std::cout << z_interpolated << std::endl;
if(z_interpolated < depth_buf_MSAA[ind][i]){
depth_buf_MSAA[ind][i] = z_interpolated;
frame_buf[ind] += 0.25 * t.getColor();
}
}
}
}
}
}
结果对比如下图: