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

时间:2016-01-21 23:22:33

标签: python opengl 3d pygame 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)))

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

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

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

首先,我不知道您使用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-圆的投影的等式

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

Angle image (the image is viewed from above)

所以现在,我们需要将此角度转换为坐标,以便在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库,它已经编写了许多此类任务,因此您可以使用该库本身,也可以打开该库的代码以从内部了解一切。