I'm using python3
I have just started learning openGL and I need some help turning the camera of your view with a mouse (Like a FPS game). Right now my program looks like i'm moving but i'm just moving the object so if you could tell me how to move the camera(forward, backwards, etc) too that would be nice. Thanks in advance
My Code:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
vertices = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 1),
(1, 1, 1, ),
(-1, -1, 1),
(-1, 1, 1),
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7),
)
surfaces = (
(0,1,2,3),
(3,2,7,6),
(6,7,5,4),
(4,5,1,0),
(1,5,7,2),
(4,0,3,6),
)
colors = (
(1,1,1),
(0,0,0),
(0,1,1),
(0,0,0),
(0,1,1),
(1,0,1),
(0,0,0),
(1,1,1),
(0,0,0),
(0,1,1),
)
def Cube():
glBegin(GL_QUADS)
for surface in surfaces:
x = 0
for vertex in surface:
x += 1
glColor3fv(colors[x])
glVertex3fv(vertices[vertex])
glEnd()
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(vertices[vertex])
glEnd()
def main():
pygame.init()
x = 0
y = 0
z = 0
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL|RESIZABLE)
pygame.event.set_grab(True)
pygame.mouse.set_visible( False )
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0, 0, -5)
glRotatef(0, 0, 0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
quit()
if event.key == pygame.K_a:
x = 0.1
elif event.key == pygame.K_d:
x = -0.1
elif event.key == pygame.K_w:
z = 0.1
elif event.key == pygame.K_s:
z = -0.1
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a and x > 0:
x = 0
elif event.key == pygame.K_d and x < 0:
x = 0
if event.key == pygame.K_w and z > 0:
z = 0
if event.key == pygame.K_s and z < 0:
z = 0
glTranslatef(x,y,z)
#glRotatef(1, 2, 3, 4)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
For a first Person movment, the camera matrix has to be incrementally changed. This means you have to calculate the current movement and current rotation matrix. Apply the movement and rotation to the camera and keep the camera for the next cycle of the loop. At the next cycle of the loop you have to use the manipulated camera from the previous cycle and you have to apply the new movement and rotation. This causes that the camera incremental changes, always based on its current position and orientation.
In a rendering, each mesh of the scene usually is transformed by the model matrix, the view matrix and the projection matrix. The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. The view matrix describes the direction and position from which the scene is looked at. The model matrix defines the location, oriantation and the relative size of a mesh in the scene.
(See Transform the modelMatrix)
In OpenGL there is one matrix stack for each matrix mode (See glMatrixMode
). The matrix modes are GL_MODELVIEW
, GL_PROJECTION
, and GL_TEXTURE
.
This means you should use the GL_PROJECTION
matrix mode when you set up the projection (gluPerspective
):
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
For the first person view matrix you need an variable where you store it:
import numpy
def IdentityMat44(): return numpy.matrix(numpy.identity(4), copy=False, dtype='float32')
view_mat = IdentityMat44()
view_mat
should be initilaized with the intial position, you can get the current model matrix by glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
:
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -5)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
glLoadIdentity()
For the rotating to the left and the right you have to perform a rotation around the y-axis by glRotatef
:
glRotatef(ry, 0, 1, 0)
To incrementally change the view matrix, you have to do the following:
glTranslatef
and glRotatef
glMultMatrixf
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
glLoadIdentity()
glTranslatef(tx,ty,tz)
glRotatef(ry, 0, 1, 0)
glMultMatrixf(view_mat)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
At the beginn an the end of your loop you should push and pop the matrix stack by glPushMatrix
and glPopMatrix
.
The final function should look somehow like this:
tx = 0
ty = 0
tz = 0
ry = 0
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
view_mat = IdentityMat44()
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -5)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
glLoadIdentity()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
quit()
if event.key == pygame.K_a: tx = 0.1
elif event.key == pygame.K_d: tx = -0.1
elif event.key == pygame.K_w: tz = 0.1
elif event.key == pygame.K_s: tz = -0.1
elif event.key == pygame.K_RIGHT: ry = 1.0
elif event.key == pygame.K_LEFT: ry = -1.0
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a and tx > 0: tx = 0
elif event.key == pygame.K_d and tx < 0: tx = 0
elif event.key == pygame.K_w and tz > 0: tz = 0
elif event.key == pygame.K_s and tz < 0: tz = 0
elif event.key == pygame.K_RIGHT and ry > 0: ry = 0.0
elif event.key == pygame.K_LEFT and ry < 0: ry = 0.0
glPushMatrix()
glLoadIdentity()
glTranslatef(tx,ty,tz)
glRotatef(ry, 0, 1, 0)
glMultMatrixf(view_mat)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Cube()
glPopMatrix()
pygame.display.flip()
pygame.time.wait(10)