使用 gluLookAt() 会导致对象旋转

Using gluLookAt() causes the objects to spin

我正在 Pygame 使用 OpenGL 制作游戏。到目前为止,我已经能够让立方体出现并制作十字线。当我尝试实现环顾四周时,事情变得……很奇怪。我会 运行 它,当我使用 gluLookAt() 功能时,甚至不移动我的鼠标它就会开始到处旋转屏幕。当我把它拿出来时,它起作用了,但我无法环顾四周。我正在做一些测试,我什至为函数设置了数据值,只是为了确保它们没有改变并且它仍然旋转。在此先感谢您提供的帮助,这是我的代码:My code on GitHub

您的代码中有 2 个问题。

  1. gluLookAt 设置视图矩阵。但这并不是全部。 gluLookAt 将视图矩阵乘以矩阵堆栈上的当前矩阵,由 glMatrixMode 选择。
    因此,您的代码将新的视图矩阵连接到现有的视图矩阵。这导致物体开始快速旋转。

在调用gluLookAt之前设置Identity matrix来解决这个问题。这导致模型视图矩阵是从头开始设置的,与其以前的状态无关。

glLoadIdentity()
gluLookAt(0, 0, 0, facing[0], facing[1], lookingZ, 0, 1, 0)
  1. 这不会完全解决你的问题,因为当你设置视图矩阵时,模型视图矩阵堆栈上的当前矩阵是投影矩阵和视图矩阵的串联.这导致 glLoadIdentity 也跳过了投影矩阵。
    这种行为可以轻松解决。将视图矩阵放在模型视图矩阵栈上(GL_MODELVIEW),将投影矩阵放在投影矩阵栈上(GL_PROJECTION):

glMatrixMode(GL_PROJECTION)
gluPerspective(45, (width/height), 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
glPushMatrix()

一个更好且完全可行的解决方案是将围绕 x 和 y 轴的旋转矩阵应用于视图矩阵。首先应用围绕 y 轴的旋转矩阵(向上向量),然后应用当前视图矩阵,最后应用 x 轴上的旋转:

view-matrix = rotate-X * view-matrix * rotate-Y

为此,当前视图矩阵必须由 glGetFloatv(GL_MODELVIEW_MATRIX):

读取
modelview = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
glRotate(-change[1]*0.1, 1, 0, 0)
glMultMatrixf(modelview)
glRotate(change[0]*0.1, 0, 1, 0)

注意,必须这样做而不是:

glLoadIdentity()
gluLookAt(0, 0, 0, facing[0], facing[1], lookingZ, 0, 1, 0)

完成 main 功能(renderingEngine.py),并进行建议的更改:

def main(world,x,y,z,width,height,renderDistance):
    pygame.init()
    pygame.display.set_mode((width,height), DOUBLEBUF | OPENGL)
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClearDepth(1.0)
    glDepthMask(GL_TRUE)
    glDepthFunc(GL_LESS)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_CULL_FACE)
    glCullFace(GL_BACK)
    glFrontFace(GL_CCW)
    glShadeModel(GL_SMOOTH)
    glDepthRange(0.0, 1.0)

    glMatrixMode(GL_PROJECTION)
    gluPerspective(45, (width/height), 0.1, 100.0)
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()

    #pygame.mouse.set_visible(False)
    facing = [0, 0, False]
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_a:
                    pygame.mouse.set_visible(True)
                    pygame.quit()
                    return # TODO: Add pause
        newMousePos = pygame.mouse.get_pos()
        change = (newMousePos[0]-(width/2), newMousePos[1]-(height/2))
        pygame.mouse.set_pos([width / 2, height / 2])
        if facing[2]:
            facing[0] -= change[0]
        else:
            facing[0] += change[0]
        facing[1] += change[1]
        while facing[0] > width:
            facing[0] = 2*width-facing[0]
            facing[2] = not facing[2]
        while facing[0] < 0:
            facing[0] = 0-facing[0]
            facing[2] = not facing[2]
        if facing[1] < 0:
            facing[1] = 0
        if facing[1] > height:
            facing[1] = height
        radius = (width**2+height**2)**.5+1
        lookingZ = (-1*facing[0]**2-facing[1]**2+radius**2)**.5
        if facing[2]:
            lookingZ *= -1

        #print(lookingZ, facing[0], facing[1], radius)
        print(facing[0], facing[1], lookingZ)

        #glLoadIdentity()
        #gluLookAt(0, 0, 0, facing[0], facing[1], lookingZ, 0, 1, 0)

        modelview = glGetFloatv(GL_MODELVIEW_MATRIX)
        glLoadIdentity()
        glRotate(-change[1]*0.1, 1, 0, 0)
        glMultMatrixf(modelview)
        glRotate(change[0]*0.1, 0, 1, 0)

        xmin = round(x-renderDistance[0])
        ymin = round(y-renderDistance[1])
        zmin = round(z-renderDistance[2])
        if xmin < 0:
            xmin = 0
        if ymin < 0:
            ymin = 0
        if zmin < 0:
            zmin = 0
        xmax = round(x+renderDistance[0])
        ymax = round(y+renderDistance[1])
        zmax = round(z+renderDistance[2])
        dims = world.dims()
        if xmax > dims[0]:
            xmax = dims[0]
        if ymax > dims[1]:
            ymax = dims[1]
        if zmax > dims[2]:
            zmax = dims[2]
        selection = world.select_data(xrange = (xmin, xmax), yrange = (ymin, ymax), zrange = (zmin, zmax))
        blocks = selection.iterate(ignore=(None,))
        glClearDepth(1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        for bl in blocks:
            locations = bl[0]
            block = bl[1]
            cube(locations[0] - x, locations[1] - y, locations[2] - z, block)
            #print(locations[0],locations[1],locations[2])

        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glOrtho(0.0, width, 0.0, height, -1.0, 1.0)
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()
        glDisable(GL_DEPTH_TEST)
        crosshair(width/2, height/2, 20)
        glEnable(GL_DEPTH_TEST)
        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()

        glCullFace(GL_BACK)
        pygame.display.flip()
        time.sleep(.01)