Games101 Asignment01
- 编写代码构建模型视图变换矩阵
Eigen::Matrix4f get_model_matrix(float rotation_angle) { Eigen::Matrix4f model = Eigen::Matrix4f::Identity(); // TODO: Implement this function // Create the model matrix for rotating the triangle around the Z axis. // Then return it. float sin_rotation_angle = sin(rotation_angle / 180.0 * acos(-1)); float cos_rotation_angle = cos(rotation_angle / 180.0 * acos(-1)); model << cos_rotation_angle, -sin_rotation_angle, 0, 0, sin_rotation_angle, cos_rotation_angle, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1; 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. // Matrix for M_persp -> M_troho Eigen::Matrix4f M_persp_troth = Eigen::Matrix4f::Identity(); M_persp_troth << zNear, 0, 0, 0, 0, zNear, 0, 0, 0, 0, zNear + zFar, -(zNear * zFar), 0, 0, 1, 0; // value of l,f,t,b; float top, bottom, left, right; top = tan(eye_fov / 2) * abs(zNear); bottom = (-1) * top; right = aspect_ratio * top; left = (-1) *right; // Matrix for move to origin. Eigen::Matrix4f M_move = Eigen::Matrix4f::Identity(); M_move << 1, 0, 0, (-1) * (left + right) / 2, 0, 1, 0, (-1) * (top + bottom) / 2, 0, 0, 1, (-1) * (zNear + zFar) / 2, 0, 0, 0, 1; // Matrix for scale. Eigen::Matrix4f M_scale = Eigen::Matrix4f::Identity(); M_scale << 2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, 2 / (zNear - zFar), 0, 0, 0, 0, 1; // Matrix for ortho transformation. Eigen::Matrix4f M_ortho = Eigen::Matrix4f::Identity(); M_ortho = M_scale * M_move; projection = M_ortho * M_persp_troth; return projection; }
- 简单分析下光栅器的代码,先从main入手
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; } // 定义一个700x700的光栅器,构造函数会根据参数创建二维数组frame_buf和deepth_buf 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}}; // 应该是三角形的id,值的意义是对应的三个顶点在向量中的下标 std::vector<Eigen::Vector3i> ind{{0, 1, 2}}; /* rst::pos_buf_id rst::rasterizer::load_positions(const std::vector<Eigen::Vector3f> &positions) { auto id = get_next_id(); pos_buf.emplace(id, positions); return {id}; } pos_buf是一个map,这个函数作用是为每个三角形坐标的顶点信息指定一个id,并存到下标为id的map中,最后返回该id */ auto pos_id = r.load_positions(pos); /* rst::ind_buf_id rst::rasterizer::load_indices(const std::vector<Eigen::Vector3i> &indices) { auto id = get_next_id(); ind_buf.emplace(id, indices); return {id}; } 迷惑,为什么要这么写 功能和load_positions类似,只不过换成了存储和标记下标 */ //关于这两个函数如何工作详见draw方法 auto ind_id = r.load_indices(ind); int key = 0; int frame_count = 0; if (command_line) { /* void rst::rasterizer::clear(rst::Buffers buff) { if ((buff & rst::Buffers::Color) == rst::Buffers::Color) { std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0}); } if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth) { std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity()); } } Buffers是一个枚举类型,clear函数的功能是如果深度或颜色参数与该枚举类中的值一样,则将深度无限大或颜色设置为(0,0,0) 使用这个枚举类型以达到初始化frame_buf与depth_buf的目的 */ r.clear(rst::Buffers::Color | rst::Buffers::Depth); // 设置变换矩阵 r.set_model(get_model_matrix(angle)); r.set_view(get_view_matrix(eye_pos)); // 这里设置了光锥的fovY为45,aspect为1(700x700),n为0.1与f为50,可以尝试修改观察变化 r.set_projection(get_projection_matrix(45, 1, 0.1, 50)); // draw函数绘制三角形 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_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("T_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; }
- draw函数用于绘制三角形
void rst::rasterizer::draw(rst::pos_buf_id pos_buffer, rst::ind_buf_id ind_buffer, rst::Primitive type) { if (type != rst::Primitive::Triangle) { throw std::runtime_error("Drawing primitives other than triangle is not implemented yet!"); } // 根据参数获得id auto& buf = pos_buf[pos_buffer.pos_id]; auto& ind = ind_buf[ind_buffer.ind_id]; // 没用到不知道是干什么的 float f1 = (100 - 0.1) / 2.0; float f2 = (100 + 0.1) / 2.0; // 计算mvp变换矩阵 Eigen::Matrix4f mvp = projection * view * model; // 遍历每一个存储的ind for (auto& i : ind) { Triangle t; // 每个点做mvp变换 Eigen::Vector4f v[] = { mvp * to_vec4(buf[i[0]], 1.0f), mvp * to_vec4(buf[i[1]], 1.0f), mvp * to_vec4(buf[i[2]], 1.0f) }; // 归一化 for (auto& vec : v) { vec /= vec.w(); } // 变换到屏幕空间 for (auto & vert : v) { vert.x() = 0.5*width*(vert.x()+1.0); vert.y() = 0.5*height*(vert.y()+1.0); vert.z() = vert.z() * f1 + f2; } // 设置三个顶点的坐标,从每个齐次坐标中取前三个值 for (int i = 0; i < 3; ++i) { t.setVertex(i, v[i].head<3>()); t.setVertex(i, v[i].head<3>()); t.setVertex(i, v[i].head<3>()); } t.setColor(0, 255.0, 0.0, 0.0); t.setColor(1, 0.0 ,255.0, 0.0); t.setColor(2, 0.0 , 0.0,255.0); /* void rst::rasterizer::rasterize_wireframe(const Triangle& t) { draw_line(t.c(), t.a()); draw_line(t.c(), t.b()); draw_line(t.b(), t.a()); } */ // 光栅化三条线段,这个应该很好算 rasterize_wireframe(t); } }
- 光栅器中使用了draw_line方法绘制线段
- draw_line是Bresenham's line algorithm,由Bresenham提出的一种精确而有效的光栅线生成算法,可用于显示线、圆和其他曲线的整数增量运算,目前最有效的线段生成算法,推导可见:https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
****
void rst::rasterizer::draw_line(Eigen::Vector3f begin, Eigen::Vector3f end) { auto x1 = begin.x(); auto y1 = begin.y(); auto x2 = end.x(); auto y2 = end.y(); Eigen::Vector3f line_color = {255, 255, 255}; int x,y,dx,dy,dx1,dy1,px,py,xe,ye,i; dx=x2-x1; dy=y2-y1; dx1=fabs(dx); dy1=fabs(dy); px=2*dy1-dx1; py=2*dx1-dy1; if(dy1<=dx1) { if(dx>=0) { x=x1; y=y1; xe=x2; } else { x=x2; y=y2; xe=x1; } Eigen::Vector3f point = Eigen::Vector3f(x, y, 1.0f); set_pixel(point,line_color); for(i=0;x<xe;i++) { x=x+1; if(px<0) { px=px+2*dy1; } else { if((dx<0 && dy<0) || (dx>0 && dy>0)) { y=y+1; } else { y=y-1; } px=px+2*(dy1-dx1); } // delay(0); Eigen::Vector3f point = Eigen::Vector3f(x, y, 1.0f); set_pixel(point,line_color); } } else { if(dy>=0) { x=x1; y=y1; ye=y2; } else { x=x2; y=y2; ye=y1; } Eigen::Vector3f point = Eigen::Vector3f(x, y, 1.0f); set_pixel(point,line_color); for(i=0;y<ye;i++) { y=y+1; if(py<=0) { py=py+2*dx1; } else { if((dx<0 && dy<0) || (dx>0 && dy>0)) { x=x+1; } else { x=x-1; } py=py+2*(dx1-dy1); } // delay(0); Eigen::Vector3f point = Eigen::Vector3f(x, y, 1.0f); set_pixel(point,line_color); } } }

浙公网安备 33010602011771号