如何使用 pygame 和 openGL 修改相机的视图
how to modify the view of the camera with pygame and openGL
我正在使用 python3
我刚开始学习 openGL,我需要一些帮助来用鼠标转动你的视角的相机(比如 FPS 游戏)。现在我的程序看起来像我在移动,但我只是在移动物体,所以如果你能告诉我如何移动相机(向前、向后等),那就太好了。提前致谢
我的代码:
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()
对于第一人称动作,必须逐步更改摄像机矩阵。这意味着您必须计算当前移动和当前旋转矩阵。将移动和旋转应用于相机,并为循环的下一个循环保留相机。在循环的下一个循环中,您必须使用上一个循环中的操纵相机,并且必须应用新的移动和旋转。这导致相机增量变化,始终基于其当前位置和方向。
在渲染中,场景的每个网格通常由模型矩阵、视图矩阵和投影矩阵进行变换。投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。视图矩阵描述了观察场景的方向和位置。模型矩阵定义场景中网格的位置、方向和相对大小。
(参见 )
在 OpenGL 中,每种矩阵模式都有一个矩阵堆栈(参见 glMatrixMode
)。矩阵模式为GL_MODELVIEW
、GL_PROJECTION
和GL_TEXTURE
.
这意味着您在设置投影时应该使用GL_PROJECTION
矩阵模式(gluPerspective
):
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
对于第一人称视图矩阵,您需要一个变量来存储它:
import numpy
def IdentityMat44(): return numpy.matrix(numpy.identity(4), copy=False, dtype='float32')
view_mat = IdentityMat44()
view_mat
需要用初始位置初始化,可以通过glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
:
得到当前模型矩阵
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -5)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
glLoadIdentity()
要向左和向右旋转,您必须围绕 y 轴旋转 glRotatef
:
glRotatef(ry, 0, 1, 0)
要逐步更改视图矩阵,您必须执行以下操作:
- 用单位矩阵初始化视图矩阵
- 通过
glTranslatef
和 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)
在循环的开始和结束处,您应该按 glPushMatrix
and glPopMatrix
.
推入和弹出矩阵堆栈
最终函数应该看起来像这样:
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)
我正在使用 python3
我刚开始学习 openGL,我需要一些帮助来用鼠标转动你的视角的相机(比如 FPS 游戏)。现在我的程序看起来像我在移动,但我只是在移动物体,所以如果你能告诉我如何移动相机(向前、向后等),那就太好了。提前致谢
我的代码:
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()
对于第一人称动作,必须逐步更改摄像机矩阵。这意味着您必须计算当前移动和当前旋转矩阵。将移动和旋转应用于相机,并为循环的下一个循环保留相机。在循环的下一个循环中,您必须使用上一个循环中的操纵相机,并且必须应用新的移动和旋转。这导致相机增量变化,始终基于其当前位置和方向。
在渲染中,场景的每个网格通常由模型矩阵、视图矩阵和投影矩阵进行变换。投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。视图矩阵描述了观察场景的方向和位置。模型矩阵定义场景中网格的位置、方向和相对大小。
(参见
在 OpenGL 中,每种矩阵模式都有一个矩阵堆栈(参见 glMatrixMode
)。矩阵模式为GL_MODELVIEW
、GL_PROJECTION
和GL_TEXTURE
.
这意味着您在设置投影时应该使用GL_PROJECTION
矩阵模式(gluPerspective
):
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
对于第一人称视图矩阵,您需要一个变量来存储它:
import numpy
def IdentityMat44(): return numpy.matrix(numpy.identity(4), copy=False, dtype='float32')
view_mat = IdentityMat44()
view_mat
需要用初始位置初始化,可以通过glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
:
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -5)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
glLoadIdentity()
要向左和向右旋转,您必须围绕 y 轴旋转 glRotatef
:
glRotatef(ry, 0, 1, 0)
要逐步更改视图矩阵,您必须执行以下操作:
- 用单位矩阵初始化视图矩阵
- 通过
glTranslatef
和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)
在循环的开始和结束处,您应该按 glPushMatrix
and glPopMatrix
.
最终函数应该看起来像这样:
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)