旋转一个不对称的截头体

Rotating an asymmetric frustum

本文关键字:不对称 一个 旋转      更新时间:2023-10-16

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

然而,上面的内容并没有给我所需的输出,而且它似乎并没有旋转投影平面,使观看平面对用户/相机来说是前置的。如何旋转投影平面,使其对用户来说变成腱前的?

我认为您确实需要了解glLoadIdentity的功能。它丢弃矩阵堆栈顶部的任何内容,并将其替换为恒等式。在这些glLoadIdentity调用之间,glTranslate和glRotate没有任何影响(除了消耗一些CPU时间和内存带宽)。类似于gluLookAt之前的glLoadIdentity渲染nil,就像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

但正如我已经说过的:只有在不需要正确变换法线的情况下,这才有效。