使用 OpenGL 进行正交投影以及如何实现相机或物体在空间中的移动

Posted

技术标签:

【中文标题】使用 OpenGL 进行正交投影以及如何实现相机或物体在空间中的移动【英文标题】:Orthographic Projection with OpenGL and how to implement camera or object movement in space 【发布时间】:2013-11-27 16:13:18 【问题描述】:

我已经使用 GL_POLYGON 制作了一个带有显示列表的立方体。我已经在坐标的原点初始化了它,这意味着在 (0,0,0) 中。在我在 glutDisplayFunc 中调用的显示函数中,我使用了代码:

glLoadIdentity();
glOrtho(0,0,0,0,1,1);
glMatrixMode(GL_MODELVIEW);

我想通过 glOrtho 使用正交投影。好吧,我的问题是:考虑到我的窗口大小为 600x600,我仍然可以看到我的立方体是否正常?

此外,我想要一些关于如何使用相关 OpenGL 函数移动我的立方体或我的相机的指南。假设我想将我的相机向后移动(到 z 轴)或我的立方体向前移动(到 - z 轴)。我该怎么做?

【问题讨论】:

您的正交投影矩阵不正常。您正在将无限小的空间投影到图像平面上。你应该什么都看不到。 【参考方案1】:

首先你还需要在调用glOrtho()之前将glMatrixMode()设置为GL_PROJECTION,所以它看起来应该是这样的。

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glOrtho(...); // Replace ... with your values

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

要移动屏幕,您只需调用以下一个或多个函数。

glTranslate*() glRotate*() glScale*()

您可以点击以上链接了解每个函数的作用方式和作用。但基本上:

glTranslate*() 平移/移动当前选定的矩阵。 glRotate*() 旋转当前选定的矩阵。 glScale*() 缩放当前选定的矩阵。

您还可以使用glPushMatrix() 和glPopMatrix() 来压入和弹出当前矩阵堆栈。


额外

另外请注意,您使用的是旧的和已弃用的函数。您不应该使用它们,而是现在假设您计算并创建自己的矩阵堆栈。


编辑

相机和物体

基本上,您可以通过结合上述功能来做到这一点。听起来可能比实际更难。

我将创建一个包含 1 个摄像头和 2 个对象的示例,主要是为了让您了解它的工作原理。

void render()

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // The Camera Rotations & Translation
    glRotatef(camera_pitch, -1f, 0f, 0f);
    glRotatef(camera_yaw, 0f, 1f, 0f);
    glTranslate(-camera_x, -camera_y, -camera_z);

    // Object 1
    glPushMatrix();
        glRotatef(...);
        glTranslate(...);

        // Render Object 1
    glPopMatrix();

    // Object 2
    glPushMatrix();
        glRotatef(...);
        glTranslate(...);

        // Render Object 2
    glPopMatrix();

再次将 ... 替换为您自己的值。

需要负向平移相机坐标的原因是因为为什么不移动相机,我们实际上是在“推动”(平移等)一切远离相机/中心的东西(从而相机始终位于中心)。

重要旋转后平移或平移后旋转的顺序很重要。当需要对相机进行变换时,您总是需要先旋转然后平移。


编辑

gluLookAt ?

gluLookAt 100% 相同,就像在我的示例中一样。

例子:

// The Camera Rotations & Translation
glRotatef(camera_pitch, -1f, 0f, 0f);
glRotatef(camera_yaw, 0f, 1f, 0f);
glTranslate(-camera_x, -camera_y, -camera_z);

这是我自己的函数,它与gluLookAt 100% 相同。 我怎么知道的?因为我看了原来的gluLookAt函数,然后做了下面这个函数。

void lookAt(float eyex, float eyey, float eyez, float centerx, float centery, float centerz)

    float dx = eyex - centerx;
    float dy = eyey - centery;
    float dz = eyez - centerz;

    float pitch = (float) Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));
    float yaw = (float) Math.atan2(dz, dx);

    pitch = -pitch;
    yaw = yaw - 1.57079633f;

    // Here you could call glLoadIdentity() if you want to reset the matrix
    // glLoadIdentity();

    glRotatef(Math.toDegrees(pitch), -1f, 0f, 0f);
    glRotatef(Math.toDegrees(yaw), 0f, 1f, 0f);
    glTranslatef(-eyex, -eyey, -eyez);

您可能需要更改 Math.* 调用,因为上面的代码不是用 C 编写的。

【讨论】:

相机怎么样?如果我想将相机移动到 z 轴的正方向,我应该调用什么函数?让我想将立方体留在坐标原点。 如果我没记错的话,glTranslate,glRotate,glScale 是用于对象的吗?不只是在您编写的这段代码中,我的意思是无处不在。 Kinda, glTranslate,glRotate,glScale 用于几何变换。因此,如果为什么要应用相机的反向 x、y、z、偏航、滚动等。在其他一切之前,它将一切都转换成一个点,就像通过相机看一样。 如果我只想移动相机怎么办。我不想在这些函数中应用反向的东西,因为我想看看 gluLookat 是如何工作的。 @johnjohn gluLookAt 100% 像我上面的例子一样工作。看看编辑后的答案,我添加了gluLookAt 函数的工作原理。

以上是关于使用 OpenGL 进行正交投影以及如何实现相机或物体在空间中的移动的主要内容,如果未能解决你的问题,请参考以下文章

正交投影中的相机位置

openGL - 正交投影矩阵

如何使用正交投影在 OpenGL Core 3.3 中绘制一个圆?

OpenGL 3+,具有定向光的正交投影

three.js正交投影照相机

OpenGL正交相机缩放无法正常工作