Games101 作业1 #旋转&投影

在作业1的代码框架中,需要我们进行操作的有这两个函数

get_model_matrix(float rotation_angle)
//逐个元素地构建模型变换矩
//阵并返回该矩阵。在此函数中,你只需要实现三维中绕 z 轴旋转的变换矩阵,
//而不用处理平移与缩放。

get_projection_matrix(float eye_fov, float aspect_ratio, floatzNear, float zFar)
//使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。

在get_model_matrix()中,实现旋转操作

在三维实体中,旋转/缩放/位移都可以用齐次坐标来进行计算

在基础的作业1中,只需要实现对z轴的旋转,因此,只需要乘上矩阵Rz(α)即可

Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    //初始化model矩阵,初始化之后,model矩阵是这样的形式:
    //1 0 0 0
    //0 1 0 0
    //0 0 1 0
    //0 0 0 1
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
    Eigen::Matrix4f rota;
    double angle=rotation_angle/180*MY_PI;    //转化为弧度制
    //实现在z轴上的旋转
    rota<<  cos(angle) , -sin(angle) , 0, 0 ,
            sin(angle) ,  cos(angle) , 0, 0 ,
            0 , 0 , 1 , 0 ,
            0 , 0 , 0 , 1 ;
    model = rota * model;    //从右往左乘
    // TODO: Implement this function
    // Create the model matrix for rotating the triangle around the Z axis.
    // Then return it.
    return model;
}

实现了旋转之后,就是投影了

投影有两种方法,一种是正交投影,一种是透视投影

正交投影出来的结果是和实机等大小的,而透视投影的结果是近大远小

实现正交投影的方法:

把要投影的物体移动到世界坐标系的原点处(因为我们的 摄像机/屏幕 也在原点处),然后对它进行缩放,缩放到与设定的屏幕大小相等就可以了。(图示是把它缩放到了一个[-1,1]^3的空间中)

这里要用到透视投影

首先把图像的每一个点进行挤压,然后再进行正交投影即可

因为在我们把图形进行挤压之后,只需要再执行正交投影就可以达到透视投影的近大远小效果了。

挤压的方法:

用下图这个矩阵乘上每一个点,即可进行挤压

(具体的推导过程可以看看闫令琪老师的视频 https://www.bilibili.com/video/BV1X7411F744?t=4307&p=4

挤压之后,就进行正交投影,即 先位移到指定坐标,再进行缩放。(乘上Mortho矩阵)

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();
    Eigen::Matrix4f persp,trans,scale;
    //进行挤压的矩阵
    persp<< zNear , 0 , 0 , 0 ,
            0 , zNear , 0 , 0 ,
            0 , 0 , zNear+zFar , -zNear*zFar ,
            0 , 0 , 1 , 0 ;
    double angle,l,r,t,b;
    angle = eye_fov/180.0*MY_PI;
    t = -zNear*tan(angle/2);   //y轴最大值
    b = -t;                    //y轴最小值
    r = t*aspect_ratio;        //x轴最大值
    l = -r;                    //x轴最小值
    //最大最小值指的是从屏幕看这个图形的上下左右的最大值
    //位移到原点
    trans<< 1 , 0 , 0 , -(r+l)/2 ,
            0 , 1 , 0 , -(t+b)/2 ,
            0 , 0 , 1 , -(zNear+zFar)/2,
            0 , 0 , 0 , 1 ;
    //缩放为长度为2的正方体(在[-1,1]^3的空间内)
    scale<< 2/(r-l) , 0 , 0 , 0 ,
            0 , 2/(t-b) , 0 , 0 ,
            0 , 0 , 2/(zNear-zFar) , 0 ,
            0 , 0 , 0 , 1 ;
    projection = scale * trans * persp * projection ;
    // TODO: Implement this function
    // Create the projection matrix for the given parameters.
    // Then return it.
    return projection;
}

最终结果: