如何成功处理OpenGL的gluLookAt功能?



尝试在我的python和pygame 3D OpenGL游戏中实现3D漫游相机是我一直在尝试做的事情,但我遇到了障碍。每次我尝试使用 gluLookAt 函数时,相机都会吓坏并四处拉扯,而 x 和 z 坐标迅速增加并从负切换到正。我正在尝试制作的游戏只是一个平坦的表面,你可以在上面走来走去。我已经实现了所有用于四处移动的控件,但没有实现相机。

对于那些不想阅读我所有编码的人来说,这里有一些总结的代码:

while True:
    matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
    camera_x = matrix[3][0]
    camera_y = matrix[3][1]
    camera_z = matrix[3][2]
    # the 3-6 ones are what the camera is looking at
    gluLookAt(camera_x, camera_y, camera_z, 0, 0, 0, 0, 1, 0)
    print("({}, {}, {})".format(int(-camera_x), int(-camera_y), int(-camera_z)))

如果上面的代码无法解决问题,这是我的完整代码:

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import os
speed = .5
def enviroment():
    glBegin(GL_QUADS)
    for surface in surfaces:
        for vertex in surface:
            glColor3fv((1, 0, 0))
            glVertex3fv(verticies[vertex])
    glEnd()
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glColor3fv((0, 1, 1))
            glVertex3fv(verticies[vertex])
    glEnd()

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
    gluPerspective(45, (display[0] / display[1]), 0.1, 400)
    glTranslatef(0.0, -3, -150)
    glRotatef(0, 0, 0, 0)
    while True:
        press = pygame.key.get_pressed()
        matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
        camera_x = matrix[3][0]
        camera_y = matrix[3][1]
        camera_z = matrix[3][2]
        # the 3-6 ones are what the camera is looking at
        gluLookAt(camera_x, camera_y, camera_z, 0, 0, 0, 0, 1, 0)
        print("({}, {}, {})".format(int(-camera_x), int(-camera_y), int(-camera_z)))
        if press[pygame.K_UP]:
            glTranslatef(0, -speed, 0)
        elif press[pygame.K_DOWN]:
            glTranslatef(0, speed, 0)
        elif press[pygame.K_w]:
            glTranslatef(0, 0, speed)
        elif press[pygame.K_s]:
            glTranslatef(0, 0, -speed)
        elif press[pygame.K_a]:
            glTranslatef(speed, 0, 0)
        elif press[pygame.K_d]:
            glTranslatef(-speed, 0, 0)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            elif event.type == KEYDOWN:
                if event.key == K_UP:
                    glTranslatef(0, -speed, 0)
                elif event.key == K_DOWN:
                    glTranslatef(0, speed, 0)
                elif event.key == K_w:
                    glTranslatef(0, 0, speed)
                elif event.key == K_s:
                    glTranslatef(0, 0, -speed)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        enviroment()
        pygame.display.flip()
        pygame.time.wait(10)
main()

任何帮助将不胜感激!

首先,我不明白你使用pygame的原因是什么。OpenGL和GLUT(OpenGL实用工具包)组合在一起,几乎包含了3D图形所需的一切(特别是在初学者级别)。因此,如果您想从3D图形开始 - GLUT几乎是您需要的一切。

关于gluLookAt函数:该功能本身需要 9 个参数,如果您想控制相机的位置 - 您需要使用前三个参数进行操作:

gluLookAt(eyeX, eyeY, eyeZ, ...)

要围绕对象旋转相机(位于 0, 0, 0),您需要更改 eyeX、eyeY 和 eyeZ,以便它们的平方和为 1(或其他一些值,具体取决于相机应与对象的距离):

eyeX^2 + eyeY^2 + eyeZ^2 = 1

这需要满足,因为这是 3D 球体的方程。

首先,您可以将eyeY变量设置为 0,以便相机仅在围绕对象的平面中旋转。那么我们需要满足这个语句:

eyeX^2 + eyeZ^2 = 1

这是将球体投影到 2D 的方程 - 一个圆

让我们介绍一个角度α,它将代表我们相机的位置。为了控制相机如何围绕物体旋转,我们将更改此角度。

角度图像(从上方查看图像

所以现在,我们需要将这个角度转换为坐标,以便在OpenGL的函数中使用。

这可以使用三角函数来完成。sin(α) 将代表我们的 Z 轴值,Cos(α) - 我们的 X 轴值。这段代码会将我们的角度转换为坐标:

eyeZ = math.sin(alpha)
eyeX = math.cos(alpha)

所以现在我们只需要使用 gluLookAt 函数:

gluLookAt(eyeX, 0, eyeZ, 0, 0, 0, 0, 1, 0)

要移动相机,您需要以您喜欢的任何方式更改α角度。

要进行更复杂的相机管理,您需要解决的不是圆等式,而是球体等式,并使用两个角度而不是一个角度。

这是一项艰巨的任务,但我可以建议您查看TRON项目(https://github.com/leviathan117/TRON/)。这是一个面向初学者的 3D 图形 Python 库,它已经编写了很多这些任务,因此您可以使用库本身或打开库的代码以查看所有内容如何从内部工作。

相关内容

  • 没有找到相关文章

最新更新