games101_Homework2
完成函数static bool insideTriangle(): 测试点是否在三角形内。
一段优雅的easy代码,没什么好说的。(但是需要修改这里传入的xy的类型为float,默认为int是想让我通过修改返回值的方式来实现MSAA:例如返回一个int值,这里传入单个像素坐标后在insideTriangle函数中实现超采样,然后返回k,再在设置颜色时* k/4)
static bool insideTriangle(float x, float y, const Vector3f* _v) { // TODO : Implement this function to check if the point p(x, y) is inside the triangle represented by _v[0], _v[1], _v[2] (a, b, c) // 如果p(x,y)与三点a、b、c构成的向量x乘同向(z坐标都为正)则在其内部 // 构建向量 Vector3f p = Vector3f(x, y, 1); Vector3f ap = p - _v[0]; Vector3f bp = p - _v[1]; Vector3f cp = p - _v[2]; Vector3f ab = _v[1] - _v[0]; Vector3f bc = _v[2] - _v[1]; Vector3f ca = _v[0] - _v[2]; // 运算x乘结果的z值 float z1 = ab.cross(ap).z(); //ab x ap float z2 = bc.cross(bp).z(); //bc x bp float z3 = ca.cross(cp).z(); //ca x cp // in Triangle return (z1 > 0 && z2 > 0 && z3 > 0) || (z1 < 0 && z2 < 0 && z3 < 0); }
rasterize_triangle(): 执行三角形栅格化算法
在采样点在三角形内部时更新z_buffer和frame_buffer(这里使用了MSAA,故颜色值需乘以一个float的k)
//Screen space rasterization void rst::rasterizer::rasterize_triangle(const Triangle& t) { auto v = t.toVector4(); // 获取三角形数据并分别传入 insideTriangle() Vector3f triangle[3]; for(int i = 0; i < 3; i++){ triangle[i] = Vector3f(v[i].x(), v[i].y(), v[i].z()); } // TODO : Find out the bounding box of current triangle. float min_x = std::min(v[0].x(), std::min(v[1].x(), v[2].x())); float max_x = std::max(v[0].x(), std::max(v[1].x(), v[2].x())); float min_y = std::min(v[0].y(), std::min(v[1].y(), v[2].y())); float max_y = 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 // frame_buffer 和 z_buffer早已定义好 for(int x = min_x; x <= max_x; x++){ for(int y = min_y; y <= max_y; y++){ // MSAA version float k = 0; if(insideTriangle(0.25 + x, 0.25 + y, triangle)) k += 0.25; if(insideTriangle(0.75 + x, 0.25 + y, triangle)) k += 0.25; if(insideTriangle(0.25 + x, 0.75 + y, triangle)) k += 0.25; if(insideTriangle(0.75 + x, 0.75 + y, triangle)) k += 0.25; if(k != 0){ // Simple Sampling //if(insideTriangle(x + 0.5, y + 0.5, 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; if(z_interpolated < depth_buf[get_index(x, y)]){ // 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[get_index(x, y)] = z_interpolated; //set_pixel(Vector3f(x, y, 1), t.getColor()); set_pixel(Vector3f(x, y, 1),k * t.getColor()); } } } } }
值得注意的是,这里zNear和zFar使用的是正值,故在main.cpp中需要修改float t = -1 * abs(zNear) * tanf(eye_fov / 2);将其y轴颠倒一下才能做出正确图形(第八节课讲这是左手右手系的原因)
注:MSAA将会导致黑线是正常的,因为我们在计算边缘像素时他的z是高于下方三角形的,但实际可能覆盖面积过小导致0.25*color,故出现黑线