How To Get Vertical Rotation In 3D Space With OpenGL?
Solution 1:
It's all a matter of the order. OpenGL is a state engine. Each operation changes a state. When you do a operation like glTranslatef
or glRotatef
then the current matrix on the matrix stack is changed.
In OpenGL there are different matrices, like the model view matrix and the projection matrix. The first thing you've to do is to separate the projection matrix and model vie matrix. THis can be done by setting the matrix mode (See glMatrixMode
):
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (screenSize[0]/screenSize[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
# [...]
When the a matrix operation is applied to the matrix stack, then the current matrix is multiplied by the new (additional) matrix, which is defined by the operation. This means glRotatef
followed by glTranslatef
dies:
current_matrix = current_matrix * rotation_matrix * translation_matrix
The issue is that if you want to apply a new translation or rotation in a first person view, the the new transformation has to be applied on the current view (current model view matrix). This mean the operations have to be performed in the opposite order, than the matrix operation does:
current_matrix = rotation_matrix * translation_matrix * current_matrix
You've tried to compensate this, by considering the current direction of view, which you've calculated by trigonometric functions. But there is alternative solution:
- read the current model view matrix by
glGetFloatv(GL_MODELVIEW_MATRIX, ...)
- init the current matrix by the identity matrix
glLoadIdentity
- evaluate the input and do the new matrix operations (
glTranslatef
/glRotatef
) - multiply the read model vie matrix to the current matirx by
glMultMatrix
current_mv_mat = (GLfloat * 16)()
glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
glLoadIdentity()
# [...] glTranslatef, glRotatef
glMultMatrixf(mv)
Even more trick is the up and down rotation which has to be performed on the current view, but sadly it should not be stated in on in the current matrix, since the movement and respectively left and right rotation should not depend on the up and down view:
current_matrix = rotation_matrix * translation_matrix * current_matrix
mdel_view_matrix = roate_updown * current_matrix
Fortunately the current matrix is manged on a stack and can be pushed and popped by glPushMatrix
/ glPopMatrix
. The up ad down rotation has to be summed up and finally applied to the view:
glPushMatrix()
current_mv_mat = (GLfloat * 16)()
glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
glLoadIdentity()
glRotatef(sum_rot_updown, 1, 0, 0)
glMultMatrixf(mv)
# [...] draw all the objects of the scene
glPopMatrix()
See the example, where I applied the suggestions to your original code:
def main():
pygame.init()
screenSize = (1500, 800)
pygame.display.set_mode(screenSize, DOUBLEBUF|OPENGL)
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (screenSize[0]/screenSize[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
rot = 0
speed = 3
radian = 57.2958
sum_rot_updown = 0
current_mv_mat = (GLfloat * 16)()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pressed = pygame.key.get_pressed()
glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
glLoadIdentity()
#==# Rotation left and right with arrow keys #==#
if pressed[pygame.K_LEFT]:
glRotatef(speed / 2, 0, -1, 0)
rot += 1
if pressed[pygame.K_RIGHT]:
glRotatef(speed / 2, 0, 1, 0)
rot -= 1
#==# Walking with WASD #==#
if pressed[pygame.K_w]:
glTranslate(0, 0, 1/speed)
if pressed[pygame.K_s]:
glTranslate(0, 0, -1/speed)
if pressed[pygame.K_a]:
glTranslate(1/speed, 0, 0)
if pressed[pygame.K_d]:
glTranslate(-1/speed, 0, 0)
glMultMatrixf(current_mv_mat)
#==# Rotation up and down with arrow keys #==#
if pressed[pygame.K_UP]:
sum_rot_updown -= speed / 2
if pressed[pygame.K_DOWN]:
sum_rot_updown += speed / 2
glPushMatrix()
glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
glLoadIdentity()
glRotatef(sum_rot_updown, 1, 0, 0)
glMultMatrixf(current_mv_mat)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
for i in range(8):
for j in range(8):
Cube(-i*2.5, -4, -j*2.5)
glPopMatrix()
pygame.display.flip()
pygame.time.wait(10)
main()
Post a Comment for "How To Get Vertical Rotation In 3D Space With OpenGL?"