创建 UI 和 glRotatef() 的问题

Problems with creating a UI and glRotatef()

我正在使用 PythonPyGame 旧版 PyOpenGL。我希望玩家能够通过按左右箭头键使用 glRotatef() 向前、向后、向左和向右四个方向环顾四周。

出现了一些问题:

  1. 一把枪(一个应用了纹理的立方体,它根据玩家面对的方向改变纹理坐标)应该始终出现在相机前面 0.5 个单位的相应 x 和 z 位置根据角度 glRotatef() 将其设置为朝向,如果我在 x 轴上移动然后向左看,它会移动到一个奇怪的位置,除非我站在房间的死角。即使我向它提供从 glGetDoublev() 获得的 x 值,当我向左和向右移动时,立方体也似乎是静止的,而当我向前移动时,枪似乎在缩放,即使我从未实现过这样的功能。

  2. 当我打电话时

    if event.type == pygame.KEYDOWN: # key pressed events
                    if event.key == pygame.K_LEFT:
                        glRotatef(-90,0,1,0)
                        if direction == 0:
                            direction = 3
                        else:
                            direction -= 1
    

    往房间左边看,我偶尔会被移到墙内,这有时会进一步影响枪的位置。

    我已经尝试添加固定的 x 和 z 变量(x_stepsz_steps),每次玩家移动它们都会增加 0.1。我不是特别确定为什么会消除 "static gun" 问题,但确实如此。但是,当我旋转相机时,仍然出现同样的问题(枪移动到一个奇怪的位置)。

    ## pygame/opengl initialisation code
    def main():
        pygame.init()
        display = (800,600)
        global displaySurface
        displaySurface = pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
        pygame.display.set_caption("Wolfenstein 4D")
        glEnable(GL_TEXTURE_2D)
        glEnable(GL_DEPTH_TEST)
        gluPerspective(45, (display[0]/display[1]),0.1,50.0)
    
    ## game loop, obtaining x,y,z positions and looking around the room
    def room1():
        direction = 3 ## 3 = forward, 2 = left, 1 = backward, 0 = right
        while True:
            pos = glGetDoublev(GL_MODELVIEW_MATRIX)
            x = pos[3][0]
            y = pos[3][1]
            z = pos[3][2]
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
    
                if event.type == pygame.KEYDOWN: # key pressed events
                    if event.key == pygame.K_LEFT:
                        glRotatef(-90,0,1,0)
                        if direction == 0:
                            direction = 3
                        else:
                            direction -= 1
                        x_steps = 0
                        z_steps = 0
    
                    if event.key == pygame.K_RIGHT:
                        glRotatef(90,0,1,0)
                        if direction == 3:
                            direction = 0
                        else:
                            direction += 1
                        x_steps = 0
                        z_steps = 0
    
    ## movement code
            spd = 0.1
            keys = pygame.key.get_pressed()
            if direction == 3:
                if keys[pygame.K_a]:
                        glTranslatef(spd,0,0)
                        x_steps -= spd
                if keys[pygame.K_d]:
                        glTranslatef(-spd,0,0)
                        x_steps += spd
                if keys[pygame.K_w]:
                        glTranslatef(0,0,spd)
                        z_steps -= spd
                if keys[pygame.K_s]:
                        glTranslatef(0,0,-spd)
                        z_steps += spd
            if direction == 2:
                if keys[pygame.K_a]:
                        glTranslatef(0,0,-spd)
                        x_steps += spd
                if keys[pygame.K_d]:
                        glTranslatef(0,0,spd)
                        x_steps -= spd
                if keys[pygame.K_w]:
                        glTranslatef(spd,0,0)
                        z_steps -= spd
                if keys[pygame.K_s]:
                        glTranslatef(-spd,0,0)
                        z_steps += spd
    
    ## gun drawing code in game loop
                if direction == 3:
                    loadTexture("gun1.png")
                    drawHUDGun(x,-0.1,z-0.5,3,0.1,0.1,0.1)
                if direction == 2:
                    loadTexture("gun.png")
                    drawHUDGun(z-0.5,-0.1,x+0.5,2,0.1,0.1,0.1)
    
    ## gun drawing function
    def drawHUDGun(x,y,z,angle,width,height,depth=0.5,color = ((1,1,1))):
        vertices = (
            (width+x,-height+y,-depth+z),
            (width+x,height+y,-depth+z),
            (-width+x,height+y,-depth+z),
            (-width+x,-height+y,-depth+z),
            (width+x,-height+y,depth+z),
            (width+x,height+y,depth+z),
            (-width+x,-height+y,depth+z),
            (-width+x,height+y,depth+z)
        )
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glBegin(GL_QUADS)
        if angle == 3:
            j = 0
        if angle == 2:
            j = 8
    
        i = 0
        for surface in surfaces:
            i += 1
            for vertex in surface:
                glColor4f(1,1,1,1)
                setTexCoord(0, texCoords, j)
                if angle == 3:
                    if i >= 0 and i < 4:
                        if j < 4:
                            j += 1
                if angle == 2:
                    if i == 2:
                        if j < 12:
                            j += 1
                glVertex3fv(vertices[vertex])
        glEnd()
        glDisable(GL_BLEND)
    
        glBegin(GL_LINES)
        for edge in edges:
            glColor3fv((0,1,0))
            for vertex in edge:
                glVertex3fv(vertices[vertex])
        glEnd()
    
    ## implementation of the functions
    
    main()
    room1()
    

    我希望无论玩家在房间的哪个方向,枪支都会在玩家前方 0.5 个单位处出现,但由于分配了不正确的 x 或 z 坐标,枪支通常不在视线范围内。

在旧版 OpenGL 中存在不同的电流矩阵。当前受矩阵运算影响的矩阵可以通过glMatrixMode. Each matrix is organized on a stack. Matrices can be pushed and popped by glPushMatrix/glPopMatrix.

选择

投影矩阵应设置为投影矩阵堆栈,视图和模型转换为模型视图矩阵堆栈:

// choose projection matrix stack
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]),0.1,50.0)

// choose modelview matrix stack, for the following matrix operations
glMatrixMode(GL_MODELVIEW)

枪应该放在第一人称视角 ("in front of you")。实现这一点的最简单方法是在视图空间中绘制枪支,这意味着您必须取消所有先前对模型视图矩阵的转换。矩阵可以替换为 identity matrix by glLoadIdentity.
将模型视图矩阵保存到堆栈上,设置单位矩阵,绘制枪并最终恢复模型视图matrix.e.g:

glPushMatrix()
glLoadIdentity()
drawHUDGun(x,-0.1,z-0.5,3,0.1,0.1,0.1)
glPopMatrix()