使用gluLookAt()导致对象旋转

时间:2019-01-22 21:32:20

标签: python python-3.x opengl pygame pyopengl

我正在使用OpenGL和Pygame制作游戏。到目前为止,我已经能够使立方体出现并制作十字准线。当我尝试实施环顾四周时,事情变得...很奇怪。我将运行它,甚至不动鼠标,当我使用compact函数时,它将开始在任何地方旋转屏幕。当我取出来时,它奏效了,但我看不到周围。我正在做一些测试,甚至将设置数据值放到函数中,以确保它们没有改变并且仍然旋转。我完全感到困惑,对OpenGL还是陌生的,而且我还不到两个月的时间来完成我的项目。预先感谢您提供的所有帮助,这是我的代码:My code on GitHub

我正在使用python 3.6 btw。

1 个答案:

答案 0 :(得分:2)

在您的代码中有2个问题。

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

在致电gluLookAt来解决此问题之前,请设置[身份矩阵]。这导致模型视图矩阵是从头开始设置的,而与它以前的状态无关。

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)