问题
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.
- 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)
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