Как создать камеру на PyOpenGL, которая может выполнять «перспективные повороты» движений мыши? - PullRequest
2 голосов
/ 15 июня 2019

Я создаю RPG с видом от первого лица и хочу поворачивать камеру в PyOpenGL при перемещении мыши (как и в некоторых других играх, таких как Minecraft).Какую функцию я могу использовать, чтобы сделать это и как?

Я пытался использовать gluLookAt(), но я не понимаю, как это работает, хотя я прошел через разные источники.Я даже не знаю, может ли это помочь.

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()

1 Ответ

1 голос
/ 15 июня 2019

Вы можете использовать glRotate для вращения вокруг оси на величину, которая определяется относительным движением мыши (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.Например:

# 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 устанавливают матрицу и умножают текущую матрицу на новую матрицу.

currentMatrix = currentMatrix * newMatrix

Идеально подходит для анимации и трансформации моделей, но это неправильный способ для движения от первого лица, когда необходимо изменить положение и точку камеры.

viewMatrix = viewTransformMatrix * viewMatrix

Комувыполняйте такие операции glGetFloatv(GL_MODELVIEW_MATRIX) и glMultMatrixf.
Инициализируйте матрицу вида с помощью gluLookAt и загрузите матрицу вида в переменную (viewMatrix) на glGetFloatv(GL_MODELVIEW_MATRIX), до основного цикла.

В главном цикле для каждого кадра:

  • загрузить Идентификационную матрицу (glLoadIdentity)
  • выполнить новые преобразования для вида (glRotatef, glTranslatef)
  • , умножить текущую матрицу вида на viewMatrix (glMultMatrixf)
  • , загрузить новую матрицу вида в viewMatrix для следующего кадра
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.Поворот поворота зависит от точки зрения.Угол должен быть суммирован, и поворот должен быть применен после того, как матрица вида была бы иначе, движение изменило бы уровень ("высота") в зависимости от угла.

viewMatrix = viewTransformMatrix * viewMatrix
finlalMatrix = lookUpDownMatrix * viewMatrix  

Для этого выНам нужно объединить матрицу вращения вверх и вниз и умножить ее на 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 или р .Если приложение приостановлено, мышь не центрируется относительно окна.

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()
...