GAMES101 作业 1——画出来的三角形是上下颠倒的,终极解释(大概?)

我的原始代码如下:

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{

    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    eye_fov = eye_fov/180.0*MY_PI;
    // M(persp) = M(ortho) * M(persp->ortho)
    // 参数列表中已有n和f,先求r, l, t, b
    float yTop = std::abs(zNear) * std::tan(eye_fov/2.0);
    float yButtom = - yTop;
    float xRight = yTop * aspect_ratio;
    float xLeft = - xRight;

    // 先求 M(ortho)
    Eigen::Matrix4f mOrthoScale;
    mOrthoScale <<     1.0/(xRight),       0,                  0,                   0,
                       0,                  1.0/(yTop),         0,                   0,
                       0,                  0,                  2.0/(zNear-zFar),    0,
                       0,                  0,                  0,                   1;
    Eigen::Matrix4f mOrthoTranslate;
    mOrthoTranslate << 1,                  0,                  0,                   0,
                       0,                  1,                  0,                   0,
                       0,                  0,                  1,                   -(zNear+zFar)/2.0,
                       0,                  0,                  0,                   1;
    // Eigen::Matrix4f mOrtho = mOrthoScale * mOrthoTranslate;

    // 再求 M(persp->ortho)
    Eigen::Matrix4f mPerspToOrtho;
    mPerspToOrtho <<   zNear,              0,                  0,                   0,
                       0,                  zNear,              0,                   0,
                       0,                  0,                  zNear+zFar,          -1.0*zNear*zFar,
                       0,                  0,                  1,                   0;
    
    // 汇总得到 M(persp)
    projection = mOrthoScale * mOrthoTranslate * mPerspToOrtho;

    return projection;
}

代码完全按照闫老师的PPT写的,把矩阵中的一些能简单算出来的参数稍微化简了。运行效果如下:

画出来的三角形是上下颠倒的,根据简单实验,修改三角形三个顶点坐标,使用非对称三角形,还可以发现运行结果是上下左右颠倒的,不过这些都不是重点。

直接说我的想法,是因为作业代码框架中给出的三角形(坐标分别是(2,0,-7), (0,2,-7), (-2,0,-7),做完view变换后的坐标,以摄像机为原点)不在作业给出的要投影的平截锥体(Frustum)内(作业中的Frustum:视场角为45°,宽高比为1,n为+0.1,f为+50):作业中三角形在z=-7平面上,而Frustum在z=+0.1~z=+50内,显然三角形不在Frustum内。我的理解是,我们做透视投影、视口变换的目的是把Frustum内的东西先整到Frustum前面那个小平面上,然后再把这个小平面通过视口变换显示到屏幕上。对于Frustum之外的东西,我认为理想情况下是不应该显示出来,因为摄影机就应该只能拍到Frustum内的东西;但实际给出的实现(也就是这些矩阵),确确实实能显示好Frustum内的东西,但对其外的东西,行为是不固定的!

作业中给出的三角形就是Frustum之外的东西,最后显示的结果就是不确定的,无论是上下颠倒还是左右颠倒都没有意义,因为大前提(在Frustum内)已经不满足了。

好了,上面是我的想法,按照这个想法,只要把作业中三角形的坐标改了,把三角形放到Frustum中,就应该可以正常显示了。三角形做完view变换后的坐标简单改成(2,0,7), (0,2,7), (-2,0,7)(只是把z坐标取反),那么原坐标应该为(2,0,12), (0,2,12), (-2,0,12)。也就是把下面这行:

std::vector<Eigen::Vector3f> pos{{2, 0, -2}, {0, 2, -2}, {-2, 0, -2}};

z坐标改成:

std::vector<Eigen::Vector3f> pos{{2, 0, 12}, {0, 2, 12}, {-2, 0, 12}};

运行看看效果:

成了。

再举一个例子。

还是上面说的那样,上课给出的矩阵只管把Frustum内的东西显示出来,其外的东西到底是也显示、还是显示错误、还是直接不显示,是不确定的!上面三角形的上下左右颠倒只是一种情况,再举一个显示一部分的例子:三角形view变换后的坐标(4,4,25), (-4,4,25), (0,12,25),这是z=25平面上的一个等腰三角形,它的下部分在Frustum内,上面一个角不在Frustum内。把代码改成:

// z=25是做了摄像机变换(view变换)之后的结果,z=30是原坐标
std::vector<Eigen::Vector3f> pos{{4, 4, 30}, {-4, 4, 30}, {0, 12, 30}};

按照我的想法,运行出来应该只显示下面在Frustum中的部分。运行验证:

确实是这样。

我把代码整了个git仓库:https://gitee.com/sheep-fish/games101-assignment1,在init提交之后就只有两次提交,都是只改了三角形坐标,然后运行出上面的几张截图。

个人水平有限,上面的仅是我的猜想,所谓“终极解释”单单为了吸人眼球,我只是有这么一个想法,然后做了上面的一点验证,就发出来了。如果我的想法是错的,我深感抱歉,还望大佬指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值