前言
本篇继续更新作业1相关,本专栏预计2个星期内搞定。
作业1相关链接
作业1简述
- 模拟基于CPU的光栅化渲染器
- 绘制要求中的三角形
作业1相关知识笔记
-
2D仿射变换和3D仿射变换矩阵推导
-
坐标系转化
-
视口变换
-
正交投影与透视投影
-
屏幕像素表示
-
光栅化算法:
直线:DDA数值微分算法、中点Bresenham算法
三角形:BoundingBox
作业1思路
注意:后面有代码展示,一定要自己先做一遍再看,而且我的设计不一定正确规范高效。
-
熟悉整个框架
最好先熟悉渲染器是怎么工作的。
整个框架结构如上图所示。其中rastrizer.hpp生成渲染器。大佬提供的框架还实现了安全绘制防止绘图顺序混淆。框架中DrawLine使用的是DDA数值微分算法,想了解怎么实现的可以看一下。
rastrizer.hpp中主要功能函数声明:
class rasterizer
{
public:
rasterizer(int w, int h);
pos_buf_id load_positions(const std::vector<Eigen::Vector3f>& positions);
ind_buf_id load_indices(const std::vector<Eigen::Vector3i>& indices);
void set_model(const Eigen::Matrix4f& m);
void set_view(const Eigen::Matrix4f& v);
void set_projection(const Eigen::Matrix4f& p);
void set_pixel(const Eigen::Vector3f& point, const Eigen::Vector3f& color);
void clear(Buffers buff);
void draw(pos_buf_id pos_buffer, ind_buf_id ind_buffer, Primitive type);
std::vector<Eigen::Vector3f>& frame_buffer() { return frame_buf; }
private:
void draw_line(Eigen::Vector3f begin, Eigen::Vector3f end);
void rasterize_wireframe(const Triangle& t);
private:
Eigen::Matrix4f model;
Eigen::Matrix4f view;
Eigen::Matrix4f projection;
std::map<int, std::vector<Eigen::Vector3f>> pos_buf;
std::map<int, std::vector<Eigen::Vector3i>> ind_buf;
std::vector<Eigen::Vector3f> frame_buf;
std::vector<float> depth_buf;
int get_index(int x, int y);
int width, height;
int next_id = 0;
int get_next_id() { return next_id++; }
};
main.cpp中模拟了render pipline。流程大致为
(1)绘制(700,700)大小的frame buffer和depth buffer.
(2)设置相机位置(0,0,5).
(3)绘制线段(三角形).
(4)下一帧清除buffer,再绘制.
此外要修正框架中rastrizer.cpp中set_pixel()中ind变量,不然会出现越界
void rst::rasterizer::set_pixel(const Eigen::Vector3f& point, const Eigen::Vector3f& color)
{
//old index: auto ind = point.y() + point.x() * width;
if (point.x() < 0 || point.x() >= width ||
point.y() < 0 || point.y() >= height) return;
auto ind = (height-1-point.y())*width + point.x();
frame_buf[ind] = color;
}
-
完善流程
在视频中已经推导过偏移矩阵,这里就直接套用参数到模型变换矩阵上即可
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. Eigen::Matrix4f rotating; float angle = rotation_angle/180*MY_PI; rotating<< std::cos(angle),-1*std::sin(angle),0,0,\ std::sin(angle),std::cos(angle),0,0,\ 0,0,1,0,\ 0,0,0,1; model=rotating*model; return model; }
构建透视投影矩阵,这个也详细推导过
(视频P4
视图矩阵推导33:08
欢迎补充)
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. Eigen::Matrix4f orthographic_matrix = Eigen::Matrix4f::Identity(); Eigen::Matrix4f scale = Eigen::Matrix4f::Identity(); Eigen::Matrix4f translate = Eigen::Matrix4f::Identity(); Eigen::Matrix4f presp_to_ortho_matrix = Eigen::Matrix4f::Identity(); double top = std::tan((eye_fov/2)/180*MY_PI/2)*zNear; double right = top*aspect_ratio; float bottom = -top; float left = -right; scale<< 2/(right-left),0,0,0,\ 0,2/(top-bottom),0,0,\ 0,0,2/(zNear-zFar),0,\ 0,0,0,1; translate<< 1,0,0,-1*(right+left)/2,\ 0,1,0,-1*(top+bottom)/2,\ 0,0,1,-1*(zNear+zFar)/2,\ 0,0,0,1; orthographic_matrix = scale*translate; presp_to_ortho_matrix<< zNear,0,0,0,\ 0,zNear,0,0,\ 0,0,zNear+zFar,-1*(zNear*zFar),\ 0,0,1,0; projection = orthographic_matrix*presp_to_ortho_matrix; return projection; }
提高部分:
Eigen::Matrix4f get_rotation(Vector3f axis,float angle){ Eigen::Matrix4f rotating = Eigen::Matrix4f::Identity(); float radian = angle/180*MY_PI; float x = axis.x(); float y = axis.y(); float z = axis.z(); float cos_angle = std::cos(radian); float sin_angle = std::sin(radian); rotating << x*x+(1-x*x)*cos_angle,x*y*(1-cos_angle)+z*sin_angle,x*z*(1-cos_angle)-y*sin_angle,0,\ x*y*(1-cos_angle)-z*sin_angle,y*y+(1-y*y)*cos_angle,y*z*(1-cos_angle)+sin_angle,0,\ x*z*(1-cos_angle)+y*sin_angle,y*z*(1-cos_angle)-x*sin_angle,z*z+(1-z*z)*cos_angle,0,\ 0,0,0,1; return rotating; }
最后效果