【问题标题】:How do I find the projection matrix that is equivalent to an orthographic matrix but gives perspective when not in xy-plane?如何找到等效于正交矩阵但在不在 xy 平面时给出透视的投影矩阵?
【发布时间】:2012-03-06 16:33:27
【问题描述】:

我在一个使用 gluOrtho2D() 设置的矩阵执行所有渲染的程序中乱七八糟。我想做的是围绕 y 轴 (0,1,0) 旋转特定纹理,以便看起来原始矩阵是由 gluPerspective() 提供的。我意识到这对于正交投影矩阵是不可能的,我将不得不设置一个新的透视投影矩阵。我希望我绘制的纹理看起来与使用正交矩阵绘制时完全相同,但有时我将它们围绕 y 轴旋转时除外。

总结一下:
当在 xy 平面中绘制形状时,如何找到与给定正交矩阵等效的透视投影矩阵,但在不在 xy 平面时给我透视?

【问题讨论】:

  • 你为什么要这样做?
  • 你的总结听起来与我之前的笔记很不一样。
  • 前面的注释可能有点不清楚,但归根结底就是摘要。我想在一个大型程序中获得透视投影,该程序使用正交投影进行所有渲染,同时更改最少的代码量。自从我上次参加计算机视觉课程以来已经有几年了,所以我很生疏。
  • 那么请看看我更新的答案,告诉我我是否正确并解决了你的问题。

标签: opengl perspective orthographic


【解决方案1】:

基本上我的理解是:当对象位于 XY 平面中时,您希望有一个透视矩阵产生与正交投影相同的图像。

让我们开始吧: 你想在 XY 平面上绘制你的平面并且你有 gluOrtho2D(-w, w, -h, h); (非对称正交投影有点困难,如果你需要它,然后说出来)。 你现在需要做的是:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(2 * atan(h / 2)  * 180.0 / PI, w / h, 1, 3);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -2);

我在这里所做的是将投影视图平截头体的中心匹配在正交投影中可见的 XY 平面截面上。

获取投影平截头体的图形和一些数学运算,您可以自己做:)


作为提醒,我将在此处留下对旧问题的回答。

您有正射投影或透视投影。你必须决定一个。 在任何轴上旋转都不会获得视角。

为什么要改变整个程序才能改变投影模式?

一种可能的解决方案: 我假设旧的 GL 具有不同的矩阵模式等等:

glMatrixMode(GL_PROJECTION); //switch to projection matrix mode
glPushMatrix(); //push the old matrix
glLoadIdentity();
//apply the perspective projection
//do your rendering
glPopMatrix(); //pop the old matrix

使用较新的 GL 方案,您将不得不自己完成大部分工作,但应该很容易。

【讨论】:

  • 程序在绘制它的纹理时做了太多其他的事情,我只是替换它看起来的投影矩阵,所以我不得不放弃这个想法并编写自己的渲染代码。这回答了这个问题,但它不应该是 gluPerspective(2*atan(h / 2), w / h, 1, 3) 吗?
  • @Leo:你说得对2 * atan我会纠正的。关于另一个问题:我的“旧”解决方案告诉您如何保存旧矩阵并在之后恢复它。
  • 优秀的答案,正是我所需要的。我的旧矩阵:GLKMatrix4MakeOrtho(-ySize, ySize, -xSize, xSize, -1024, 1024);我的新矩阵:GLKMatrix4MakePerspective(M_PI_2, ySize / xSize, 30, 10000); GLKMatrix4MakeTranslation(0, 0, -xSize);当相机角度垂直且每个对象的 z=0 时,结果是相同的。
  • 2 * atan(h / 2) *180.0/PI
【解决方案2】:

这是否可能以某种简单的方式实现,而无需将所有程序都转换为使用 gluPerspective()?

我已经厌倦了告诉这个,但是:

投影不是一次性定义的,然后在整个渲染过程中强制执行。您可以随时切换它,任何高级渲染方案都会在单个帧中多次执行此操作。

我认为大多数新手对此感到困惑:

reshape(width, height):
    glViewport(0,0,width,height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    projection_setup()

他们看到在 reshape 函数中完成了投影,并认为这是唯一可以这样做的地方。 请跟我说话: 投影矩阵只是用于绘图的某种状态。它可以像当前颜色或纹理一样轻松更改。

只需在绘制之前根据需要设置特定绘图命令序列所需的投影即可。

【讨论】:

  • 对不起,我意识到我的问题写得很糟糕,因为我很着急。我想要的是一个投影矩阵,它为在 xy 平面中绘制的对象提供与旧正交矩阵相同的外观,但为不在 xy 平面中的对象提供透视投影。
【解决方案3】:

即使您的投影矩阵是正交的,也可能具有透视效果,即围绕 x 或 y 轴旋转,诀窍是在任何其他视图转换之前/之后将您的视图矩阵乘以这个魔术矩阵:

// The matrix is
// -z,  0,  x,  0
//  0, -z,  y,  0
//  0,  0,  1,  0
//  0,  0,  1, -z

在哪里:

  • x 是视口宽度的一半,
  • y 是视口高度的一半,
  • z 可以是除 -0 之外的任何负数。

几个注意事项:

  1. 如果您调用 glRotate*,则此矩阵首先出现,因为这些内置调用是右手乘法。如果您按照教科书上的建议使用左手乘法跟踪您自己的视图矩阵,则该矩阵排在最后。无论哪种方式,这个矩阵实际上都会乘以你的正交项目矩阵,所以你也可以预先计算
  2. z实际上是模拟的z深度,所以它的幅度越大,物体越远,因此旋转看起来更像是正交的。 Z 不能为正,因为这会使 NDC 中的 w 为负,OpenGL 不允许这样做,它会被剪裁,所以什么都不会绘制
  3. 最后,没有魔法,这个矩阵只是一个补偿,在你这样做之后: M(ortho) X M(magic),你得到一个透视矩阵
  4. 如果 99% 的代码是正交的,但只有一两个地方需要透视效果,那么这个技巧至关重要,那么你不需要在两种模式之间切换,如果你使用固定管道,GL_PROJECTION_MATRIX 将保持不变
  5. 这个矩阵取自 Android 开源项目,所以希望这会给你很大的信心

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-08
    • 2015-08-06
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 2014-08-01
    • 2021-04-09
    • 1970-01-01
    相关资源
    最近更新 更多