C++ Ortho和Persp是反向Z深度符号?

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,等等 佩尔

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
等于
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;
}