Using gluLookAt() causes the objects to spin

醉酒当歌 提交于 2021-02-19 07:54:18

问题


I am making a game using OpenGL with Pygame. So far I was able to make cubes appear and make a cross hair. When I tried to implement looking around, things got... weird. I would run it and without even moving my mouse it would start spinning the screen everywhere when I used the gluLookAt() function. When I took that out, it worked but I couldn't look around. I was doing some testing and I even put in set data values to the function just to make sure that they were not changing and it still spun. Thanks in advance for whatever you are able to help me with and here is my code: My code on GitHub


回答1:


In your code there are 2 issues.

  1. gluLookAt sets up a view matrix. But this is not all. gluLookAt multiplies the view matrix to the current matrix on the matrix stack, which is chosen by glMatrixMode.
    So your code concatenates the new view matrix to the existing view matrix. This causes that the objects start to spin rapidly.

Set the Identity matrix before you call gluLookAt to solve this issue. This causes that the model view matrix is set from scratch, independent on its former state.

glLoadIdentity()
gluLookAt(0, 0, 0, facing[0], facing[1], lookingZ, 0, 1, 0)
  1. This won't solve you issue completely, because at the point when you set the view matrix, then current matrix on the model view matrix stack is the concatenation of the projection matirx and the view matrix. This cause the glLoadIdentity also skips the projection matrix.
    This behaviour can be solved with ease. Put the view matrix on the model view matrix stack (GL_MODELVIEW) and the projection matrix to the projection matrix stack (GL_PROJECTION):

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

An much better and completely working solution is to apply a rotation matrix around the x and y axis to the view matrix. First apply the rotation matrix around the y axis (up vector) then the current view matrix and finally the rotation on the x axis:

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

For this the current view matrix has to be read by 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)

Note, this has to be done instead of:

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

Complete main function (renderingEngine.py), with the suggested changes:

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)


来源:https://stackoverflow.com/questions/54316746/using-glulookat-causes-the-objects-to-spin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!