【问题标题】:Rotating an asymmetric frustum旋转不对称平截头体
【发布时间】:2018-02-11 22:15:49
【问题描述】:

在我的程序中,我在投影矩阵中定义了一个不对称平截头体,它根据用户的位置而变化。对于所有 z 值都在同一位置的平面,我的程序可以正常工作。但是,如果观察平面有点旋转(沿 Y 方向旋转),然后我通过在 ModelView 矩阵中执行 glRotate 来旋转相机。

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
    glFrustum(topLeftX, bottomRightX, bottomRightY, topLeftY, camNear, camFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
    gluLookAt(xHeadPosition, yHeadPosition, zHead, xHeadPosition, yHeadPosition, zHead -1 , 0, 1, 0);
glTranslatef(400, 0); //Rotating with the right side of the plane as the pivot
    glRotatef(yRotation, 0, 1, 0);
glTranslatef(-400, 0);

但是,我想在投影中做同样的事情以保持 MV 矩阵的清洁。我尝试执行以下操作:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
    glTranslatef(400, 0); // Pre-multiplication here as opposed to post-mulitplication in MV matrix
        glRotatef(yRotation, 0, 1, 0);
    glTranslatef(-400, 0);
glFrustum(topLeftX, bottomRightX, bottomRightY, topLeftY, camNear, camFar);
glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
        gluLookAt(xHeadPosition, yHeadPosition, zHead, xHeadPosition, yHeadPosition, zHead -1 , 0, 1, 0);

但是,以上内容并没有给我所需的输出,而且它似乎没有旋转投影平面以使观察平面垂直于用户/相机。如何旋转投影平面以使其垂直于用户?

【问题讨论】:

  • 那可不简单。
  • 为什么不用this answer to another question of yours中的链接呢?它为您提供了将屏幕定位在空间中任意位置和方向所需的一切。
  • @AndreasHaferburg :我找不到在该代码中处理任意方向的部分。除此之外,这个答案有很大帮助。你能指定在代码中的哪个位置处理任意方向吗? P.S 我正在考虑多个屏幕的线条,其中一些屏幕的四个角的 Z 值可能不同。

标签: c++ algorithm opengl 3d


【解决方案1】:

我认为您确实需要了解 glLoadIdentity 的作用。它丢弃矩阵堆栈顶部的任何内容并用标识替换它。在这些 glLoadIdentity 调用之间,那些 glTranslate 和 glRotate 没有任何影响(除了消耗一些 CPU 时间和内存带宽)。与 glFrustum 所做的 gluLookAt 呈现 nil 之前的 glLoadIdentity 类似。

我的建议:找一本关于线性代数的书,尤其是矩阵数学,好好学习一下。然后你拿起一本关于 3D 图形数学的书,了解如何将之前从书中学到的抽象概念付诸实践。

那么你应该熟悉一下 OpenGL 顶点变换管道。

终于明白拥有“干净”的模型视图矩阵没有意义。您在第一个代码 sn-p 中拥有的就是您想要的:一个可以构建的基础矩阵。


更新

好的,这里你的想法有一个小误解:

glLoadIdentity();
// Pre-multiplication here as opposed to post-mulitplication in MV matrix
glTranslatef(400, 0);
glRotatef(yRotation, 0, 1, 0);
glTranslatef(-400, 0);
glFrustum(topLeftX, bottomRightX, bottomRightY, topLeftY, camNear, camFar);

是什么让你认为你应该在这里预乘?转化链是

p_view = MV · p_local

p_clip =  P · p_view

你可以把它收缩成

p_clip = P · MV · p_local

模型视图和投影矩阵的分离不是为了位置变换,而是为了法线变换。后面的步骤仅用于照明目的。但要使其工作,投影矩阵必须仅包含投影部分,而不包含任何视口位置。或者换句话说,这个 glTranslate → glRotate → glTranslate 部分不属于那里。无论如何,如果您决定“哦,我不需要照明”(无论出于何种原因,您都必须将其放在对 glFustum 的调用之后。为什么?因为这就是原因:

在第一种情况下,您的模型视图 MV 和投影 P 矩阵是

MV = I · gluLookAt · glTranslate · glRotate · glTranslate

 P = I · glFrustum

因为I · x = x 我们可以省略I。所以位置变换是

v_clip = P · MV · v_local =

       = glFrustum · gluLookAt · glTranslate · glRotate · glTranslate · glRotate · v_local

仅关于位置(但不是法线),您可以将模型视图和投影变换之间的分割放在上述变换链中的任何点。在您想要的情况下(顺便说一句,这没有多大意义),这将在 *v_local* 之前。所以

P = glFrustum · gluLookAt · glTranslate · glRotate · glTranslate · glRotate

但就像我已经说过的:这仅在您不需要正确转换法线时才有效。

【讨论】:

  • 我忘了在第二个代码中写glMatrixMode,因为我刚刚输入它并且没有复制粘贴。我也熟悉 glLoadIdentity 和 Model->View->Projection->Screen 的转换管道。但是缺少glMatrixMode 让我看起来像是在投影矩阵中调用gluLookAt。我希望代码现在有意义,但我正在尝试实现与第一个代码相同的旋转,以针对我的一个需求构建适应矩阵。
  • 感谢您的解释。更清楚了,但我注意到即使我将glTranslate(..); glRotate(..); glTranslate(..)' 放在你提到的 glFrustum 之后,它仍然没有给我任何输出。旋转矩阵乘法是根据我在这里得到的bit.ly/1b4b2fC 的解释来旋转不同屏幕的投影,即对于旋转的屏幕,我应该选择 glFrustum() * 旋转 * 平移。这是错的吗?在理想情况下,如何旋转投影以使其与用户垂直?
  • @user1240679:嗯,从技术上讲,旋转和翻译是有序的,但说实话,这样做很麻烦。这更容易通过简单地写下正确的矩阵来完成。但这是我最好在专门的教程中写的主题,因为它需要几个中间水平的知识,这根本不适合 StackOverflow 答案(我的猫刚刚占用了我的绘图板,所以我不能画漂亮的图片现在)。
猜你喜欢
  • 2013-07-09
  • 2015-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 2013-12-05
  • 2010-10-10
相关资源
最近更新 更多