opengl - 透视矩阵背后的数学原理

标签 opengl matrix perspectivecamera

我想创建自己的 mvp 矩阵作为练习。

auto lookAt(Vec)(const Vec eye, const Vec center, const Vec up)
if(isVector!Vec && Vec.dimension is 3){
    auto z = (eye - center).unit;
    auto x = cross(up.unit, z);
    auto y = cross(z, x);
    alias Mat = Matrix!(Vec.Type, 4, 4);
    alias Vec4 = Vector!(Vec.Type, 4);
    return Mat(Vec4(x, 0),
               Vec4(y, 0),
               Vec4(z, 0),
               Vec4(0, 0, 0, 1)) * translate(-eye);
}

View 转换相当简单,我将其设置为现在沿着负 Z 轴查看。

但是我在使用透视矩阵时遇到了一些麻烦。

y' = 1 / (tan(fov/2) * z
x' = 1 / (ar * tan(fov/2) * z

其中 x'y' 是新的扭曲值。所以我想出了这个矩阵

Mat4f projection(float fov, float ar, float near, float far){
  import std.math: tan;
  auto tanHalfAngle = tan(fov/2.0f);
  return Mat4f(
      Vec4f(1.0f / (ar * tanHalfAngle) , 0, 0, 0),
      Vec4f(0, 1.0f / tanHalfAngle, 0, 0),
      Vec4f(0, 0, 1, 0),
      Vec4f(0, 0, -1, 0));
}

我目前只是将其设置为 Z 值始终为 -1。但我犯了一个小错误,因为现在我除以 -Z

问题是上面的矩阵起作用了。我当前正在渲染一个旋转立方体,除了深度值之外,一切看起来都是正确的。

但我真的想要这个矩阵

Mat4f projection(float fov, float ar, float near, float far){
  import std.math: tan;
  auto tanHalfAngle = tan(fov/2.0f);
  return Mat4f(
      Vec4f(1.0f / (ar * tanHalfAngle) , 0, 0, 0),
      Vec4f(0, 1.0f / tanHalfAngle, 0, 0),
      Vec4f(0, 0, -1, 0),
      Vec4f(0, 0, 1, 0));
}

但是立方体不再出现在屏幕上,我不明白为什么。

auto view = lookAt(Vec3f(0, 0, -5), Vec3f(0, 0, 0), Vec3f(0, 1, 0));
auto proj = projection(PI/2, 4.0f/3.0f, 0.1f, 100);

我设置测试值

auto v = proj * view * Vec4f(0.5,0.5,0.5,1);

这是我用第一个矩阵除以 -Z

得到的输出
Vec(-0.375, 0.5, -5.5, 5.5)
Vec(-0.0681818, 0.0909091, -1) // divided by w

这是我用第二个矩阵除以 Z

得到的输出
Vec(-0.375, 0.5, 5.5, -5.5)
Vec(0.0681818, -0.0909091, -1) //divided by w

唯一改变的是标志。

但是为什么我可以看到第一个矩阵的立方体,但第二个矩阵却看不到任何内容?

最佳答案

OpenGL的默认裁剪规则是在裁剪空间中制定的,因为满足以下不等式的所有点都位于视锥体内:

-w <= x, y, z <= w

请注意,这简单地排除了 w < 0 的任何点,因为那么 -w 将 > w,因此无法满足。

The view transformation was rather simple, I set it up so that I now look along the negative Z axis.

事实并非如此。 View 矩阵单独定义观察方向,投影矩阵也有影响。当使用标准透视投影时,投影矩阵的最后一行可以简单地解释为投影主轴的方向向量 - 因此它定义了眼睛空间中的观看方向向量。经典GL投影使用(0 0 -1 0) ,所以-z将是观看方向。

View 矩阵现在的工作是放置相机并旋转场景,以便将预期的世界空间观看方向映射到投影矩阵正在使用的眼睛空间观看方向。

当您翻转投影矩阵以除以 z 时而不是-z ,这当然意味着它会朝那个方向看。由于您没有调整 View 矩阵以遵循该约定,因此您的相机现在完全沿着与 View 矩阵设置相反的方向进行查看。位于相机“前面”的点z_eye < 0都会有负面的w_clip ,并被近平面剪裁。

关于opengl - 透视矩阵背后的数学原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36517414/

相关文章:

c++ - opengl 土壤中的多线程支持

opengl - 从深度缓冲区和任意 View 投影矩阵重建世界坐标

algorithm - Matlab 中的简单文本阅读器 (OCR)

python - 使用 Python 计算(符号)雅可比矩阵的逆

opencv - 针孔相机模型坐标系

c++ - FPS 计数器的奇怪问题 - 在较新的计算机上限制为 60fps

c++ - GLFW 洋红色导致意外行为

c - 三重指针作为参数 - 矩阵乘法

opengl - 在 opengl 中,为什么我们必须在 gluLookAt 之前执行 gluPerspective?

javascript - 从 obj 文件中加载一个 3d 对象,并使用 Three.Js 将其放入相机中