目录
任务
本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。这里仅仅专注于如何得到矩阵,具体的渲染流程会在作业2中详解。
get_model_matrix(float rotation_angle): 逐个元素地构建模型变换矩阵并返回该矩阵。在此函数中,你只需要实现三维中绕 z
轴旋转的变换矩阵,而不用处理平移与缩放。
get_projection_matrix(float eye_fov, float aspect_ratio, float
zNear, float zFar):
使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。
所有的和数学有关的推导,这里不再说明,基本直接套用结果,不清楚可以重新看一遍games101的课程对应的知识。之后的文章亦是如此。
实现
get_model_matrix
绕x,y,z轴的变换矩阵如下,算出两个三角函数值后直接代入即可
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity(); //创建一个单位矩阵
float angle = rotation_angle / 180.0f * MY_PI; //将角度制的角度转化为弧度制的角度,因为c++默认的三角函数用的是弧度制
float s = std::sin(angle);
float c = std::cos(angle);
model << c, -s, 0, 0, s, c, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0; //根据旋转矩阵的公式,直接给模型矩阵赋值
return model;
}
get_projection_matrix
zNear是近平面到摄像机的距离,已知视角,可以根据正切函数求出一半的高度,最后乘2就可以得到近平面的高度,根据宽高比,求出近平面的宽度。再根据推导出的矩阵,代入数据即可求得所需的结果。
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
Eigen::Matrix4f persp_to_ortho; //公式中的persp->ortho矩阵
Eigen::Matrix4f ortho; //ortho矩阵
float height = zNear*std::tan(eye_fov/2) * 2; //视锥体挤成立方体,立方体的高
float width = height * aspect_ratio; //立方体的宽
persp_to_ortho << zNear, 0, 0, 0, //根据公式求得persp->ortho矩阵
0,zNear,0,0,
0,0,zNear + zFar,-zNear*zFar,
0,0,1,0;
ortho << 2.0/width , 0 ,0, 0, //根据公式求得ortho矩阵,这里直接将平移和缩放两步写在一起了
0, 2.0/height,0,0,
0,0,2.0/(zNear-zFar),-(zNear+zFar)/(zNear-zFar),
0,0,0,1;
projection = ortho * persp_to_ortho * projection;
return projection;
}
提高项:get_rotation
这里采用罗德里格斯旋转公式,代码如下
旋转函数
Eigen::Matrix4f get_rotation(Eigen::Vector3f n,float angle){
float cos_a = std::cos(angle);
float sin_a = std::sin(angle);
Eigen::Matrix3f I = Eigen::Matrix3f::Identity();
Eigen::Matrix3f t;
t << 0 , -n.z() , n.y(),
n.z() , 0 , -n.x(),
-n.y() , n.x(), 0;
Eigen::Matrix3f rotateMatrix = cos_a * I +(1-cos_a)*n*n.transpose() + sin_a*t;
Eigen::Matrix4f finalMatrix = Eigen::Matrix4f::Identity();
finalMatrix.block<3,3>(0,0) = rotateMatrix; //这里以矩阵0,0位置开始,将3*3的位置写入rotateMatrix
return finalMatrix;
}
修改后的模型矩阵函数,这里绕着指定的轴(0.5000,0.2000,0.8426)旋转
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity(); //创建一个单位矩阵
float angle = rotation_angle / 180.0f * MY_PI; //将角度制的角度转化为弧度制的角度,因为c++默认的三角函数用的是弧度制
Eigen::Vector3f n = {0.5000,0.2000,0.8426};
Eigen::Matrix4f model = get_rotation(n,angle);
return model;
}
结果
初始的状态
绕z轴旋转
绕指定的轴n旋转