games101 第一次作业 三角形的光栅化
第一次games101的课程作业
非常简单,涉及投影变换和罗德里格斯旋转公式
注意,我已经添加了提高内容,加入了罗德里格斯旋转公式:
核心代码修改如下:
底下这个代码块为提高部分,实现罗德里格斯旋转公式:
Eigen::Matrix4f get_rotation(Eigen::Vector4f axis,float rotation_angle) { rotation_angle = rotation_angle/180*3.1415926; Eigen::Matrix4f rotation = Eigen::Matrix4f::Identity(); Eigen::Matrix4f tmp; tmp<<0,-axis[2],axis[1],0,axis[2],0,-axis[0],0,-axis[1],axis[0],0,0,0,0,0,1; rotation = std::cos(rotation_angle)*rotation + (1-std::cos(rotation_angle))*axis*axis.transpose()+std::sin(rotation_angle)*tmp; return rotation; }
下面是普通的旋转矩阵:
可以看到,是绕z轴的旋转
Eigen::Matrix4f get_model_matrix(float rotation_angle) { Eigen::Matrix4f model = Eigen::Matrix4f::Identity(); Eigen::Matrix4f Rotated; rotation_angle = rotation_angle/180*3.1415926; Rotated << std::cos(rotation_angle), -sin(rotation_angle), 0, 0, std::sin(rotation_angle), std::cos(rotation_angle), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1; model = model*Rotated; // TODO: Implement this function // Create the model matrix for rotating the triangle around the Z axis. // Then return it. return model; }
下面实现投影矩阵:
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar) { // Students will implement this function Eigen::Matrix4f projection = Eigen::Matrix4f::Identity(); // TODO: Implement this function // Create the projection matrix for the given parameters. // Then return it. float pi = 3.1415926; float t = std::tan(eye_fov/2/180.0f*pi)*zNear; float r = t*aspect_ratio; float l = -r; float b = -t; Eigen::Matrix4f Mtranslate; Mtranslate <<1,0,0,-(r+l)/2,0,1,0,-(t+b)/2,0,0,1,-(zNear+zFar)/2,0,0,0,1; Eigen::Matrix4f Mortho; Mortho << 2/(r-l),0,0,0,0,2/(t-b),0,0,0,0,2/(zNear-zFar),0,0,0,0,1; Mortho = Mortho*Mtranslate; Eigen::Matrix4f Mpers; Mpers<<zNear,0,0,0,0,zNear,0,0,0,0,zNear+zFar,-(zNear*zFar),0,0,1,0; projection=projection*Mortho*Mpers; return projection; }
因为我已经做了提高部分,其实可以对比一下普通的部分,其实实现的效果是一样的
注意主函数,我修改了其中两行,使用我自己的get_rotation函数
int main(int argc, const char** argv) { float angle = 0; bool command_line = false; std::string filename = "output.png"; if (argc >= 3) { command_line = true; angle = std::stof(argv[2]); // -r by default if (argc == 4) { filename = std::string(argv[3]); } else return 0; } rst::rasterizer r(700, 700); Eigen::Vector3f eye_pos = {0, 0, 5}; std::vector<Eigen::Vector3f> pos{{2, 0, -2}, {0, 2, -2}, {-2, 0, -2}}; std::vector<Eigen::Vector3i> ind{{0, 1, 2}}; auto pos_id = r.load_positions(pos); auto ind_id = r.load_indices(ind); int key = 0; int frame_count = 0; Eigen::Vector4f a(0,0,1,0); if (command_line) { r.clear(rst::Buffers::Color | rst::Buffers::Depth); r.set_model(get_rotation(a,angle)); // 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, rst::Primitive::Triangle); cv::Mat image(700, 700, CV_32FC3, r.frame_buffer().data()); image.convertTo(image, CV_8UC3, 1.0f); cv::imwrite(filename, image); return 0; } while (key != 27) { r.clear(rst::Buffers::Color | rst::Buffers::Depth); r.set_model(get_rotation(a,angle)); // 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, rst::Primitive::Triangle); cv::Mat image(700, 700, CV_32FC3, r.frame_buffer().data()); image.convertTo(image, CV_8UC3, 1.0f); cv::imshow("image", image); key = cv::waitKey(10); std::cout << "frame count: " << frame_count++ << '\n'; if (key == 'a') { angle += 10; } else if (key == 'd') { angle -= 10; } } return 0; }
最后实现效果如下
成功实现三角形的绘制
而且可以旋转