gluPerspective()/ glm :: perspective()中的近/远剪裁平面如何工作?

时间:2017-12-19 16:19:40

标签: c++ opengl glm-math perspectivecamera homogenous-transformation

我对标准透视投影矩阵的工作原理提出了疑问,即gluPerspective()glm::perspective()。具体来说,我想知道近/远剪裁平面。

我的印象是,在使用透视矩阵转换点后,近剪裁平面上的对象映射到Z值-1,远剪裁平面附近的对象映射到Z值为1.

例如,假设您有一个位于原点的摄像头,朝向正Z轴方向,近距离剪裁平面为1.0,远剪裁平面设置为2.0。然后我会期望具有“世界”Z坐标在1.0和2.0之间的东西将被转换为具有-1.0和1.0之间的投影坐标。

换句话说,我希望这个C ++代码:

#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

using namespace glm;

void print_vec(vec4 pnt) {
    std::cout << "(" << pnt.x << ", " << pnt.y << ", " << pnt.z << ")" << "\n";
}

int main() {
    mat4x4 view = lookAt(
            vec3(0.0f, 0.0f, 0.0f),   // eye at origin
            vec3(0.0f, 0.0f, 1.0f),   // looking towards +Z
            vec3(0.0f, 1.0f, 0.0f));  // up is +Y

    mat4x4 projection = perspective(
            radians(90.0f),  // field of view
            1.0f,            // aspect ratio
            1.0f,            // near clipping plane
            2.0f);           // far clipping plane

    // transformation matrix for world coordinates
    mat4x4 vp = projection * view; 

    // points (0,0,1), (0,0,1.5) and (0,0,2) in homogeneous coordinates
    print_vec(vp * vec4(0.0f, 0.0f, 1.0f, 1.0f));
    print_vec(vp * vec4(0.0f, 0.0f, 1.5f, 1.0f));
    print_vec(vp * vec4(0.0f, 0.0f, 2.0f, 1.0f));
}

打印出来

(0, 0, -1)
(0, 0, 0)
(0, 0, 1)

但事实并非如此。它打印出来:

(0, 0, -1)
(0, 0, 0.5)
(0, 0, 2)

我不明白为什么。近似的平面投影像我期望的那样投影,但是投影时平面中间的点更接近背面,并且远剪裁平面上的点完全在[-1,1]范围之外。

我认为有一些基本的数学问题我只是缺少,所以这就是为什么我问你们好人。

(顺便说一句,我正在研究的东西实际上是用Rust编写的,而不是C ++,但是为了这个测试,我转而使用C ++,只是为了确保Rust实现中没有错误或其他什么。)< / p>

1 个答案:

答案 0 :(得分:1)

  

但事实并非如此。它打印出来:

(0, 0, -1)
(0, 0, 0.5)
(0, 0, 2)

这是错误的,因为结果不是vec3类型,而是类型为vec4的{​​{3}}:

(0, 0, -1, 1)
(0, 0, 0.5, 1.5)
(0, 0, 2, 2)

你必须做Homogeneous coordinate,然后你才能得到预期的结果:

(0/1,   0/1,   -1/1)
(0/1.5, 0/1.5,  0.5/1.5)
(0/2,   0/2,    2/2)