3

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

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);

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

4

1 回答 1

1

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

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

然后,您应该熟悉 OpenGL 顶点转换管道。

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


更新

好的,在这里您的想法中有一个小误解:

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我们可以省略我。所以位置变换将是

v_clip = P · MV · v_local =

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

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

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

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

于 2013-07-21T09:06:02.513 回答