如何在PyOpenGL上创建可以进行“透视旋转"的摄像机.鼠标移动? [英] How create a camera on PyOpenGL that can do "perspective rotations" on mouse movements?
问题描述
我正在创建第一人称视角的RPG,并且我想在移动鼠标时在PyOpenGL中旋转相机(就像其他游戏一样(如Minecraft)).我可以使用什么功能来执行此操作?
I am creating a first-person view RPG and I want to rotate the camera in PyOpenGL when I move the mouse (just like some other games like Minecraft). What function can I use to do this and how?
我尝试使用gluLookAt()
,但是尽管经历了不同的采访,但我不明白它的工作原理.我什至不知道是否能帮上忙.
I tried to use gluLookAt()
but I don't understand how it works although I went through different sources. I don't even know if it can help.
import sys,pygame
from OpenGL.GL import *
from OpenGL.GLU import *
cmddown = False
#...
keypress = pygame.key.get_pressed()#Move using WASD
if keypress[pygame.K_w]:
glTranslatef(0,0,0.1)
if keypress[pygame.K_s]:
glTranslatef(0,0,-0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1,0,0)
if keypress[pygame.K_a]:
glTranslatef(0.1,0,0)
mouse_movement = pygame.mouse.get_rel()#Get mouse event
#This is where the "look around" should be happen
pygame.display.flip()
推荐答案
您可以使用 pygame.mouse.get_rel()
):
You can use glRotate
to rotate around an axis, by an amount which is given by the relative mouse movement (pygame.mouse.get_rel()
):
mouseMove = pygame.mouse.get_rel()
glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0)
但是那不会令您满意,因为如果鼠标离开窗口,该解决方案就可以继续工作了.
您必须通过将鼠标置于屏幕中央在每帧中pygame.mouse.set_pos()
.通过 pygame.MOUSEMOTION
事件获得摩斯动作.例如:
But that won't satisfy you, becaus the solution want work any more, if the mouse leaves the window.
You've to center the mouse in the middle of the screen by pygame.mouse.set_pos()
in every frame. Get the mous movment by the pygame.MOUSEMOTION
event. e.g.:
# init mouse movement and center mouse on screen
displayCenter = [scree.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)
paused = False
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN:
run = False
if event.key == pygame.K_PAUSE or event.key == pygame.K_p:
paused = not paused
pygame.mouse.set_pos(displayCenter)
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
if not paused:
pygame.mouse.set_pos(displayCenter)
不是,该操作类似 glRotate
和 glTranslate
设置矩阵,然后将当前矩阵乘以新矩阵.
Not, that operations like glRotate
and glTranslate
set a matrix and multiply the current matrix by the new matrix.
currentMatrix = currentMatrix * newMatrix
这对于模型动画和变换是完美的,但是对于第一人称移动来说,这是错误的方式,因为在这种情况下,必须更改相机的位置和指向.
That is perfect for model animations and transformations, but it is the wrong way for a first person movement, where the camera position and point of has to be changed.
viewMatrix = viewTransformMatrix * viewMatrix
要做类似的操作 glGetFloatv(GL_MODELVIEW_MATRIX)
和 glMultMatrixf
.
通过 gluLookAt
初始化视图矩阵并在主循环之前通过glGetFloatv(GL_MODELVIEW_MATRIX)
将视图矩阵加载到变量(viewMatrix
).
To do operations like that glGetFloatv(GL_MODELVIEW_MATRIX)
and glMultMatrixf
.
Initialize the view matrix by gluLookAt
and load the view matrix to a variable (viewMatrix
) by glGetFloatv(GL_MODELVIEW_MATRIX)
, before the main loop.
在每个帧的主循环中:
- 加载身份矩阵(
- load the Identity matrix (
glLoadIdentity
) - do the new transformations to the the view (
glRotatef
,glTranslatef
) - multiply the current view matrix by
viewMatrix
(glMultMatrixf
) - load the new view matrix to
viewMatrix
for the next frame
glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
# [...]
run = True
while run:
# [...]
# init the view matrix
glLoadIdentity()
# apply the movment
if keypress[pygame.K_w]:
glTranslatef(0,0,0.1)
if keypress[pygame.K_s]:
glTranslatef(0,0,-0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1,0,0)
if keypress[pygame.K_a]:
glTranslatef(0.1,0,0)
# apply the roation
glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0)
# multiply the current matrix by the get the new view matrix and store the final vie matrix
glMultMatrixf(viewMatrix)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
要进行上下查找,必须围绕x轴进行最终旋转.旋转的枢轴取决于角度. 必须对角度进行求和,并且必须在视图矩阵之后应用旋转,否则运动会根据角度改变(高度")水平.
For the look up und down, you've to apply a final rotation around the x axis. The pivot of the rotation depends on the point of view. The angle has to be summed up, and the rotation must be applied after the view matrix was else the movement would change the ("height") level dependent on the angle.
viewMatrix = viewTransformMatrix * viewMatrix
finlalMatrix = lookUpDownMatrix * viewMatrix
为此,您必须合并上下旋转矩阵并将其乘以vieMatrix
To do so, you've to ally the up and down rotaion matrix and multiply it by vieMatrix
up_down_angle = 0.0
run = True
while run:
# [...]
# init model view matrix
glLoadIdentity()
# apply the look up and down
up_down_angle += mouseMove[1]*0.1
glRotatef(up_down_angle, 1.0, 0.0, 0.0)
# init the view matrix
glPushMatrix()
glLoadIdentity()
# calculate new `viewMatrix`
# [...]
# apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)
请参见下面的示例程序,以演示该过程.
请注意,程序将鼠标保留在窗口的中央,因此您不能再移动"鼠标.
因此,可以通过 ESC 或 return 停止应用程序.
可以通过 pause 或 p 暂停该应用程序.当应用程序暂停时,鼠标不在窗口居中.
See the following example program, which demonstrates the process.
Note, the program keeps the mouse in the center of the window, so you can't "move" the mouse any more.
Therefore the application can be stopped by ESC or return.
The application can be paused by pause or p. ehen the application is paused, then the mouse is not centered to the window.
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import math
pygame.init()
display = (400, 300)
scree = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1])
sphere = gluNewQuadric()
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
# init mouse movement and center mouse on screen
displayCenter = [scree.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)
up_down_angle = 0.0
paused = False
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN:
run = False
if event.key == pygame.K_PAUSE or event.key == pygame.K_p:
paused = not paused
pygame.mouse.set_pos(displayCenter)
if not paused:
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
pygame.mouse.set_pos(displayCenter)
if not paused:
# get keys
keypress = pygame.key.get_pressed()
#mouseMove = pygame.mouse.get_rel()
# init model view matrix
glLoadIdentity()
# apply the look up and down
up_down_angle += mouseMove[1]*0.1
glRotatef(up_down_angle, 1.0, 0.0, 0.0)
# init the view matrix
glPushMatrix()
glLoadIdentity()
# apply the movment
if keypress[pygame.K_w]:
glTranslatef(0,0,0.1)
if keypress[pygame.K_s]:
glTranslatef(0,0,-0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1,0,0)
if keypress[pygame.K_a]:
glTranslatef(0.1,0,0)
# apply the left and right rotation
glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0)
# multiply the current matrix by the get the new view matrix and store the final vie matrix
glMultMatrixf(viewMatrix)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
# apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)
glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0])
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glColor4f(0.5, 0.5, 0.5, 1)
glBegin(GL_QUADS)
glVertex3f(-10, -10, -2)
glVertex3f(10, -10, -2)
glVertex3f(10, 10, -2)
glVertex3f(-10, 10, -2)
glEnd()
glTranslatef(-1.5, 0, 0)
glColor4f(0.5, 0.2, 0.2, 1)
gluSphere(sphere, 1.0, 32, 16)
glTranslatef(3, 0, 0)
glColor4f(0.2, 0.2, 0.5, 1)
gluSphere(sphere, 1.0, 32, 16)
glPopMatrix()
pygame.display.flip()
pygame.time.wait(10)
pygame.quit()
这篇关于如何在PyOpenGL上创建可以进行“透视旋转"的摄像机.鼠标移动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!