GAMES101 作业1

作业目标是把三角形投影到屏幕上,并绕z轴旋转(进阶:绕任意轴旋转)。

get_model_matrix

// TODO: Implement this function
// Create the model matrix for rotating the triangle around the Z axis.
// Then return it.
/**
 * @brief  控制model旋转的矩阵
 * @note   
 * @param  rotation_angle: 绕z轴旋转角度
 * @retval model矩阵
 */
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
    float theta=rotation_angle/180*MY_PI;//弧度制转角度制
    model<<
    cos(theta),-sin(theta),0.0,0.0,
    sin(theta),cos(theta),0.0,0.0,
    0.0,0.0,1.0,0.0,
    0.0,0.0,0.0,1.0;

    return model;
}

/**
 * @brief  绕旋转轴dir旋转rotation_angle度,dir过圆心
 * @note   直接套罗戈里德斯公式
 * @param  dir: 过圆心的旋转轴
 * @param  rotation_angle: 旋转角度
 * @retval 
 *
*/
Eigen::Matrix4f get_model_matrix(Eigen::Vector3f dir,float rotation_angle)
{
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();

    float theta=rotation_angle/180*MY_PI;
    float nx=dir(0);
    float ny=dir(1);
    float nz=dir(2);

    Eigen::Matrix3f N = Eigen::Matrix3f::Identity();

    N<<
    0.0,-nz,ny,
    nz,0.0,-nx,
    -ny,nx,0.0;

    Eigen::Matrix3f matrix = Eigen::Matrix3f::Identity();
    matrix = cos(theta) * Eigen::Matrix3f::Identity() + (1-cos(theta)) * dir * dir.transpose() + sin(theta) * N;

    // 转为齐次坐标
    model << 
    matrix(0,0), matrix(0,1), matrix(0,2), 0,
    matrix(1,0), matrix(1,1), matrix(1,2), 0,
    matrix(2,0), matrix(2,1), matrix(2,2), 0,
    0,0,0,1;

    return model;
}

get_projection_matrix

推导透视投影转为正方体过程中得用到齐次坐标将x,y,z同乘系数才能解出来(也就是必须按照闫佬讲的那个过程),直接解的话解不出来。
但是这里有个问题是求解的应该是相机坐标系下(相机在原点,坐标系由LookAt确定,朝向-z轴),near平面和far平面应该在负半轴,也就是视锥里的点的z坐标:$ -f<z_0<-n $。所以带入齐次坐标求解的时候要注意。

// TODO: Implement this function
// Create the projection matrix for the given parameters.
// Then return it.
/**
 * @brief  将透视投影转为[-1,1]xyz范围内的正方体(正交投影)这整个是在相机坐标系下的计算
 * @note   
 * @param  eye_fov: 相机的fov
 * @param  aspect_ratio: 宽度和高度比
 * @param  zNear: 距离相机的Near平面距离
 * @param  zFar: 距离相机的Far平面距离
 * @retval 透视投影投影矩阵转为正方体(正交投影)的矩阵
 */
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{

    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
    // 视锥变为长方体: near平面的坐标不变,far平面的z坐标不变,(x0,y0,z0)->(n/f*x0,n/f*y0,z0)
    Eigen::Matrix4f matrix1 = Eigen::Matrix4f::Identity();
    // matrix1<< //与下相同9
    // zNear,0.0,0.0,0.0,
    // 0.0,zNear,0.0,0.0,
    // 0.0,0.0,zFar+zNear,zNear*zFar,
    // 0.0,0.0,-1.0,0.0;

    matrix1<<
    -zNear,0.0,0.0,0.0,
    0.0,-zNear,0.0,0.0,
    0.0,0.0,-(zFar+zNear),-zNear*zFar,
    0.0,0.0,1.0,0.0;

    // 变为xyz[-1,1]范围内的正方体
    // 先把长方体移动到原点
    Eigen::Matrix4f matrix2= Eigen::Matrix4f::Identity();
    matrix2<<
    1.0,0.0,0.0,0.0,
    0.0,1.0,0.0,0.0,
    0.0,0.0,1.0,(zNear+zFar)/2,// 此时点都在z的负半轴
    0.0,0.0,0.0,1.0;

    // 缩放
    float theta=eye_fov/180*MY_PI;// fov的角度
    float h=2*tan(theta/2)*zNear;
    float w=h*aspect_ratio;
    Eigen::Matrix4f matrix3= Eigen::Matrix4f::Identity();
    matrix3<<
    2/h,0.0,0.0,0.0,
    0.0,2/w,0.0,0.0,
    0.0,0.0,2/(zFar-zNear),0.0,
    0.0,0.0,0.0,1.0;

    projection=matrix3*matrix2*matrix1;

    return projection;
}

这里百思不得其解的时候,还测试了一下相机LookAt的朝向:
https://learnopengl-cn.github.io/01 Getting started/09 Camera/#look-at

Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)
{
    Eigen::Matrix4f view = Eigen::Matrix4f::Identity();

    Eigen::Vector3f original(0,0,0);
    Eigen::Vector3f dir=(eye_pos-original).normalized();// 一般方向向量是定义的相机朝向的反方向
    Eigen::Vector3f up(0,1,0);//定义一个向上的方向
    // Eigen::Vector3f right=dir.cross(up).normalized();
    Eigen::Vector3f right=up.cross(dir).normalized();

    view<<
    right(0),right(1),right(2),0.0,
    up(0),up(1),up(2),0.0,
    dir(0),dir(1),dir(2),0.0,
    0,0,0,1;


    Eigen::Matrix4f translate;
    translate << 
    1, 0, 0, -eye_pos[0], 
    0, 1, 0, -eye_pos[1], 
    0, 0, 1, -eye_pos[2],
    0, 0, 0, 1;

    view = translate * view;

    return view;
}

其实这个倒三角问题困扰了我很久,从OpenCV到OpenGL,从相机LookAT坐标系包括看了一些网上的教程,感觉都不太能说服我。现在我自己给出的这个解释我认为是能够说服我的。这下也贴出看到的一些教程:
https://zhuanlan.zhihu.com/p/618620569
https://zhuanlan.zhihu.com/p/448904350
https://zhuanlan.zhihu.com/p/618878989

运行结果

Eigen一些操作

最后就是Eigen的一些操作

初始化

Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
Eigen::Matrix4f model(0,0,0,1);

取值

// Vector4f
std::cout<<v(0)<<","<<v(1)<<","<<v(2)<<","<<v(3)<<std::endl;
std::cout<<v.x()<<","<<v.y()<<","<<v.z()<<","<<v.w()<<std::endl;

// Matrix4f
std::cout<<v(0,0)<<std::endl;
matrix3<<
   1,0.0,0.0,0.0,
    0.0,1,0.0,0.0,
    0.0,0.0,1,0.0,
    0.0,0.0,0.0,1.0;

赋值

// Vector4f
v(0)=1;

// Matrix4f
v(0,0)=1;

posted @ 2024-03-30 12:31  小帆敲代码  阅读(14)  评论(0编辑  收藏  举报