旋转不对称的平截头体

时间:2013-07-21 07:54:43

标签: c++ algorithm opengl 3d

在我的程序中,我在投影矩阵中定义了一个非对称平截头体,它根据用户的位置而变化。如果一个平面的所有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);

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

1 个答案:

答案 0 :(得分:1)

我认为你真的需要了解glLoadIdentity的作用。它丢弃矩阵堆栈顶部的任何内容,并用身份替换它。在那些glLoadIdentity调用之间,那些glTranslate和glRotate没有任何影响(除了消耗一些CPU时间和内存带宽)。类似于gluLookAt渲染之前的glLoadIdentity,无论glFrustum是什么。

我的建议:拿一本关于线性代数的书,特别是矩阵数学,通过它来完成。然后你会拿一本关于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我们可以省略I.因此位置变换将是

v_clip = P · MV · v_local =

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

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

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

但是就像我已经说过的那样:只有在你不需要正常转换法线时才有效。