C++ Ortho和Persp是反向Z深度符号?
OpenGL的NDC坐标形成一个立方体,谁的C++ Ortho和Persp是反向Z深度符号?,c++,opengl,3d,glm-math,C++,Opengl,3d,Glm Math,OpenGL的NDC坐标形成一个立方体,谁的-Z侧压在屏幕上,而+Z侧压得最远 当我使用 // ortho arguments are: left, right, bottom, top, near, far pos = pos * glm::ortho<float>(-1, 1, -1, 1, -1, 1); //正交参数有:左、右、下、上、近、远 pos=pos*glm::正交(-1,1,-1,1,-1,1); …反映了pos的z组件-1变为1,10变为-10,等等 佩尔
-Z
侧压在屏幕上,而+Z
侧压得最远
当我使用
// ortho arguments are: left, right, bottom, top, near, far
pos = pos * glm::ortho<float>(-1, 1, -1, 1, -1, 1);
//正交参数有:左、右、下、上、近、远
pos=pos*glm::正交(-1,1,-1,1,-1,1);
…反映了pos
的z
组件-1变为1,10变为-10,等等
佩尔斯普也做了类似的事情,这有点奇怪?如果一个位置的z
等于near
,我希望它停在NDC立方体面向屏幕的平面上,但是它的符号被任意翻转;它甚至没有降落在最远的一侧
为什么会这样
OpenGL的NDC坐标形成一个立方体,谁的-Z面压在屏幕上,而+Z面离屏幕最远
我看了宋浩安关于OpenGL转换的教程,以确保不会讲一些愚蠢的东西
在透视投影中,将截断棱锥体圆台(眼睛坐标)中的三维点映射到立方体(NDC);x坐标范围从[l,r]到[-1,1],y坐标范围从[b,t]到[-1,1],z坐标范围从[-n,-f]到[-1,1]
请注意,眼睛坐标是在右手坐标系中定义的,但NDC使用左手坐标系。也就是说,原点处的摄影机在眼睛空间中沿-Z轴查看,但在NDC中沿+Z轴查看
(这是我的。)
他为此提供了以下很好的说明:
所以,我得出的结论是
glm::ortho<float>(-1, 1, -1, 1, -1, 1);
因为我手头没有glm
,所以我从github()上的源代码中获取了相关的代码行。在源代码中挖掘了一会儿,我终于在以下代码中找到了glm::ortho()
的实现:
啊!!z按-1缩放,即z值在x-y平面上镜像(如预期)
因此,OP的观察完全正确合理:
…pos的z分量被反射-1变为1,10变为-10,等等
最难的部分是: 为什么会这样 我个人的猜测是:一位发明了所有GL东西的SGI大师明智地做到了这一点 另一种猜测是:在眼睛空间中,x轴指向右侧,y轴指向上方。将其转换为屏幕坐标,y轴应指向下方(因为像素通常/技术上从左上角开始寻址)。所以,这引入了另一个镜像轴,它改变了坐标系的惯用手(再次) 这有点令人不满意,因此我在谷歌上搜索并发现了这个(重复?):
宋浩安(Song Ho Ahn)做了一个关于转换的很好的教程:我会定期重温,以理清思路。所有这些变化有时让我头晕。但这一次我很确定,因为我最近做了一个玩具项目,我“手动”制作了所有东西:。早在GL 1.0时代,我们对透视矩阵使用
gluPerspective
,它反转Z轴。GLM math是在很长一段时间后创建的,我猜他们希望保持兼容性。如果您是在+Z
或-Z
方向查看,这实际上并不重要,因为NDC中的深度值仍然是[-1,+1]
您只需相应地设置正面和深度测试功能。。。所以,如果你想你只是反转Z轴回缩放。。。
| 1 0 0 0 |
| 0 1 0 0 |
| 0 0 -1 0 |
| 0 0 0 1 |
template<typename T>
GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar)
{
mat<4, 4, T, defaultp> Result(1);
Result[0][0] = static_cast<T>(2) / (right - left);
Result[1][1] = static_cast<T>(2) / (top - bottom);
Result[2][2] = static_cast<T>(1) / (zFar - zNear);
Result[3][0] = - (right + left) / (right - left);
Result[3][1] = - (top + bottom) / (top - bottom);
Result[3][2] = - zNear / (zFar - zNear);
return Result;
}
#include <iomanip>
#include <iostream>
struct Mat4x4 {
double values[4][4];
Mat4x4() { }
Mat4x4(double val)
{
values[0][0] = val; values[0][1] = 0.0; values[0][2] = 0.0; values[0][3] = 0.0;
values[1][0] = 0.0; values[1][1] = val; values[1][2] = 0.0; values[1][3] = 0.0;
values[2][0] = 0.0; values[2][1] = 0.0; values[2][2] = val; values[2][3] = 0.0;
values[3][0] = 0.0; values[3][1] = 0.0; values[3][2] = 0.0; values[3][3] = val;
}
double* operator[](unsigned i) { return values[i]; }
const double* operator[](unsigned i) const { return values[i]; }
};
Mat4x4 ortho(
double left, double right, double bottom, double top, double zNear, double zFar)
{
Mat4x4 result(1.0);
result[0][0] = 2.0 / (right - left);
result[1][1] = 2.0 / (top - bottom);
result[2][2] = - 1;
result[3][0] = - (right + left) / (right - left);
result[3][1] = - (top + bottom) / (top - bottom);
return result;
}
std::ostream& operator<<(std::ostream &out, const Mat4x4 &mat)
{
for (unsigned i = 0; i < 4; ++i) {
for (unsigned j = 0; j < 4; ++j) {
out << std::fixed << std::setprecision(3) << std::setw(8) << mat[i][j];
}
out << '\n';
}
return out;
}
int main()
{
Mat4x4 matO = ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
std::cout << matO;
return 0;
}