gluPerspective()/glm::perspective() 中的 near/far 裁剪平面如何工作?
How does near/far clipping planes in gluPerspective()/glm::perspective() work?
我有一个关于标准透视投影矩阵如何工作的问题,您从 gluPerspective()
或 glm::perspective()
获得的那个。具体来说,我想知道 near/far 裁剪平面。
我的印象是,在用透视矩阵变换一个点后,近裁剪平面上的对象映射到 Z 值 -1,而远裁剪平面附近的对象映射到 Z 值 1。
例如,假设您有一个位于原点的相机,沿 Z 轴正方向观察,近裁剪平面设置为 1.0,远裁剪平面设置为 2.0。然后,我希望 "world" 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 实现中没有错误或其他东西。 )
But it doesn't. It prints out this:
(0, 0, -1)
(0, 0, 0.5)
(0, 0, 2)
这是错误的,因为结果不是 vec3
类型,而是 vec4
类型的 Homogeneous coordinate:
(0, 0, -1, 1)
(0, 0, 0.5, 1.5)
(0, 0, 2, 2)
你必须做一个 Perspective divide 然后你会得到预期的结果:
(0/1, 0/1, -1/1)
(0/1.5, 0/1.5, 0.5/1.5)
(0/2, 0/2, 2/2)
我有一个关于标准透视投影矩阵如何工作的问题,您从 gluPerspective()
或 glm::perspective()
获得的那个。具体来说,我想知道 near/far 裁剪平面。
我的印象是,在用透视矩阵变换一个点后,近裁剪平面上的对象映射到 Z 值 -1,而远裁剪平面附近的对象映射到 Z 值 1。
例如,假设您有一个位于原点的相机,沿 Z 轴正方向观察,近裁剪平面设置为 1.0,远裁剪平面设置为 2.0。然后,我希望 "world" 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 实现中没有错误或其他东西。 )
But it doesn't. It prints out this:
(0, 0, -1)
(0, 0, 0.5)
(0, 0, 2)
这是错误的,因为结果不是 vec3
类型,而是 vec4
类型的 Homogeneous coordinate:
(0, 0, -1, 1)
(0, 0, 0.5, 1.5)
(0, 0, 2, 2)
你必须做一个 Perspective divide 然后你会得到预期的结果:
(0/1, 0/1, -1/1)
(0/1.5, 0/1.5, 0.5/1.5)
(0/2, 0/2, 2/2)