0

尝试在我的 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()

任何帮助,将不胜感激!

4

1 回答 1

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 的方程 - 一个圆

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

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

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

于 2019-09-27T21:11:37.410 回答