如何在PyOpenGL上创建可以进行“透视旋转"的摄像机.鼠标移动? [英] How create a camera on PyOpenGL that can do "perspective rotations" on mouse movements?

查看:241
本文介绍了如何在PyOpenGL上创建可以进行“透视旋转"的摄像机.鼠标移动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建第一人称视角的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()

推荐答案

您可以使用

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆