From 8da5c621697cfb7b5a4f1f3ba494db2b92ae82e4 Mon Sep 17 00:00:00 2001 From: Hinageshi01 <2247001665@qq.com> Date: Sat, 21 Oct 2023 18:46:14 +0800 Subject: [PATCH] Assignment2 down. --- Frame/Source/Assignment/Assignment1/main.cpp | 5 +- Frame/Source/Assignment/Assignment2/main.cpp | 111 +++++++++--------- .../Assignment/Assignment2/rasterizer.cpp | 102 ++++++++++++++-- 3 files changed, 148 insertions(+), 70 deletions(-) diff --git a/Frame/Source/Assignment/Assignment1/main.cpp b/Frame/Source/Assignment/Assignment1/main.cpp index ad063d3a..abadd616 100644 --- a/Frame/Source/Assignment/Assignment1/main.cpp +++ b/Frame/Source/Assignment/Assignment1/main.cpp @@ -62,8 +62,9 @@ Eigen::Matrix4f get_projection_matrix(float fov, float aspect, float near, float 0.0f, 0.0f, 0.0f, 1.0f; Eigen::Matrix4f Morthographic = Mrotate * Mtrans; + Eigen::Matrix4f Mprojection = Morthographic * Mp2o; - return Morthographic * Mp2o; + return Mprojection; } Eigen::Matrix4f get_rotation(float angle, Vector3f n) @@ -91,7 +92,7 @@ Eigen::Matrix4f get_rotation(float angle, Vector3f n) return ret; } -int main(int argc, const char **argv) +int main() { float angle = 0.0f; rst::rasterizer r(700, 700); diff --git a/Frame/Source/Assignment/Assignment2/main.cpp b/Frame/Source/Assignment/Assignment2/main.cpp index 7bb5225d..085426fd 100644 --- a/Frame/Source/Assignment/Assignment2/main.cpp +++ b/Frame/Source/Assignment/Assignment2/main.cpp @@ -28,56 +28,71 @@ Eigen::Matrix4f get_model_matrix(float rotation_angle) return model; } -Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar) +Eigen::Matrix4f get_projection_matrix(float fov, float aspect, float near, float far) { - // TODO: Copy-paste your implementation from the previous assignment. - Eigen::Matrix4f projection; - - return projection; + // 由 frustum 的定义得 top 与 right + float top = std::tan(fov * 0.5f * MY_PI / 180.0f) * std::abs(near); + float right = aspect * top; + // 由相机此时的位置方向得 bottom = -top 与 left = -right + float bottom = -top; + float left = -right; + + Eigen::Matrix4f Mp2o; + Mp2o << + near, 0.0f, 0.0f, 0.0f, + 0.0f, near, 0.0f, 0.0f, + 0.0f, 0.0f, near + far, -near * far, + 0.0f, 0.0f, 1.0f, 0.0f; + + Eigen::Matrix4f Mtrans; + Mtrans << + 1.0f, 0.0f, 0.0f, (right + left) * -0.5f, + 0.0f, 1.0f, 0.0f, (top + bottom) * -0.5f, + 0.0f, 0.0f, 1.0f, (near + far) * -0.5f, + 0.0f, 0.0f, 0.0f, 1.0f; + + Eigen::Matrix4f Mrotate; + Mrotate << + 2.0f / (right - left), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f / (top - bottom), 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f / (near - far), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f; + + Eigen::Matrix4f Morthographic = Mrotate * Mtrans; + Eigen::Matrix4f Mprojection = Morthographic * Mp2o; + + return Mprojection; } -int main(int argc, const char** argv) +int main() { float angle = 0; - bool command_line = false; - std::string filename = "output.png"; - - if (argc == 2) - { - command_line = true; - filename = std::string(argv[1]); - } - rst::rasterizer r(700, 700); - Eigen::Vector3f eye_pos = {0,0,5}; - std::vector pos - { - {2, 0, -2}, - {0, 2, -2}, - {-2, 0, -2}, - {3.5, -1, -5}, - {2.5, 1.5, -5}, - {-1, 0.5, -5} - }; - + { + {2, 0, -2}, + {0, 2, -2}, + {-2, 0, -2}, + {3.5, -1, -5}, + {2.5, 1.5, -5}, + {-1, 0.5, -5} + }; std::vector ind - { - {0, 1, 2}, - {3, 4, 5} - }; - + { + {0, 1, 2}, + {3, 4, 5} + }; std::vector cols - { - {217.0, 238.0, 185.0}, - {217.0, 238.0, 185.0}, - {217.0, 238.0, 185.0}, - {185.0, 217.0, 238.0}, - {185.0, 217.0, 238.0}, - {185.0, 217.0, 238.0} - }; + { + {217.0, 238.0, 185.0}, + {217.0, 238.0, 185.0}, + {217.0, 238.0, 185.0}, + {185.0, 217.0, 238.0}, + {185.0, 217.0, 238.0}, + {185.0, 217.0, 238.0} + }; auto pos_id = r.load_positions(pos); auto ind_id = r.load_indices(ind); @@ -86,24 +101,6 @@ int main(int argc, const char** argv) int key = 0; int frame_count = 0; - if (command_line) - { - r.clear(rst::Buffers::Color | rst::Buffers::Depth); - - r.set_model(get_model_matrix(angle)); - r.set_view(get_view_matrix(eye_pos)); - r.set_projection(get_projection_matrix(45, 1, 0.1, 50)); - - r.draw(pos_id, ind_id, col_id, rst::Primitive::Triangle); - cv::Mat image(700, 700, CV_32FC3, r.frame_buffer().data()); - image.convertTo(image, CV_8UC3, 1.0f); - cv::cvtColor(image, image, cv::COLOR_RGB2BGR); - - cv::imwrite(filename, image); - - return 0; - } - while(key != 27) { r.clear(rst::Buffers::Color | rst::Buffers::Depth); diff --git a/Frame/Source/Assignment/Assignment2/rasterizer.cpp b/Frame/Source/Assignment/Assignment2/rasterizer.cpp index ac151f9a..9cf2f52c 100644 --- a/Frame/Source/Assignment/Assignment2/rasterizer.cpp +++ b/Frame/Source/Assignment/Assignment2/rasterizer.cpp @@ -40,9 +40,27 @@ auto to_vec4(const Eigen::Vector3f& v3, float w = 1.0f) } -static bool insideTriangle(int x, int y, const Vector3f* _v) +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] + // 此时位于屏幕空间,保证 z 分量一致即可 + Eigen::Vector3f point = { x, y, 0.0f }; + Eigen::Vector3f vertex_a = { v[0].x(), v[0].y(), 0.0f }; + Eigen::Vector3f vertex_b = { v[1].x(), v[1].y(), 0.0f }; + Eigen::Vector3f vertex_c = { v[2].x(), v[2].y(), 0.0f }; + + Eigen::Vector3f vector_ab = vertex_b - vertex_a; + Eigen::Vector3f vector_bc = vertex_c - vertex_b; + Eigen::Vector3f vector_ca = vertex_a - vertex_c; + Eigen::Vector3f vector_ap = point - vertex_a; + Eigen::Vector3f vector_bp = point - vertex_b; + Eigen::Vector3f vector_cp = point - vertex_c; + + float crossz1 = vector_ab.cross(vector_ap).z(); + float crossz2 = vector_bc.cross(vector_bp).z(); + float crossz3 = vector_ca.cross(vector_cp).z(); + + return (crossz1 <= 0.0f && crossz2 <= 0.0f && crossz3 <= 0.0f) || + (crossz1 >= 0.0f && crossz2 >= 0.0f && crossz3 >= 0.0f); } static std::tuple computeBarycentric2D(float x, float y, const Vector3f* v) @@ -106,16 +124,78 @@ void rst::rasterizer::draw(pos_buf_id pos_buffer, ind_buf_id ind_buffer, col_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 - - // 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; + // AABB 应当由整数的像素下标索引定义 + uint16_t min_x = std::numeric_limits::max(); + uint16_t max_x = std::numeric_limits::min(); + uint16_t min_y = std::numeric_limits::max(); + uint16_t max_y = std::numeric_limits::min(); + for (size_t i = 0; i < 3; ++i) + { + min_x = std::min(static_cast(std::floor(v[i].x())), min_x); + max_x = std::max(static_cast(std::ceil(v[i].x())), max_x); + min_y = std::min(static_cast(std::floor(v[i].y())), min_y); + max_y = std::max(static_cast(std::ceil(v[i].y())), max_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. + for (uint16_t pos_x = min_x; pos_x <= max_x; ++pos_x) + { + for (uint16_t pos_y = min_y; pos_y <= max_y; ++pos_y) + { + size_t index = static_cast(get_index(static_cast(pos_x), static_cast(pos_y))); + float &depth = depth_buf[index]; + + // SSAA 所采样的四个子像素相对于像素左下角坐标的偏移量 + static const std::vector s_offsets = { {0.25f, 0.25f}, {0.75f, 0.25f}, {0.25f, 0.75f}, {0.75f, 0.75f} }; + constexpr uint8_t SubPixelCount = 4; + assert(s_offsets.size() == SubPixelCount); + + // 用于计算子像素贡献值 + uint8_t activeColor = 0; + uint8_t activeDepth = 0; + Eigen::Vector3f finalColor = { 0.0f, 0.0f , 0.0f }; + float finalDepth = 0.0f; + + for (const auto& offset : s_offsets) + { + float subPos_x = static_cast(pos_x) + offset.x(); + float subPos_y = static_cast(pos_y) + offset.y(); + + // 获取子像素的深度插值 + auto [alpha, beta, gamma] = computeBarycentric2D(subPos_x, subPos_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 (insideTriangle(subPos_x, subPos_y, t.v)) + { + if (z_interpolated < depth) + { + // 只有同时通过了 inside 测试与深度测试才会对颜色有贡献 + ++activeColor; + finalColor += t.getColor(); + } + // 只要通过 inside 测试就会对深度有贡献 + ++activeDepth; + finalDepth += z_interpolated; + } + } + + finalColor /= static_cast(activeColor); + finalDepth /= static_cast(activeDepth); + + // 没有通过测试的子像素依旧应当对颜色与深度产生贡献, + // 按理来说其值应从 frame_buf_ssaax4 与 depth_buf_ssaax4 中获取。 + // 鉴于框架本身较为简陋,这里意思到位即可,没有必要魔改框架增加理解难度。 + // finalColor += static_cast(SubPixelCount - activeColor) / static_cast(SubPixelCount) * frame_buf_ssaax4[subIndex]; + // finalDepth += static_cast(SubPixelCount - activeDepth) / static_cast(SubPixelCount) * depth_buf_ssaax4[subIndex]; + + if (finalDepth < depth) + { + depth = finalDepth; + set_pixel(Eigen::Vector3f{ static_cast(pos_x), static_cast(pos_y), finalDepth }, finalColor); + } + } + } } void rst::rasterizer::set_model(const Eigen::Matrix4f& m)