混淆将 PyOpenGL 从 PyGame 转移到 PyQt5
Confusion transferring PyOpenGL from PyGame to PyQt5
我正在尝试将 PyGame PyOpenGL tutorial 的示例代码拼凑成 PyQt5 QOpenGLWidget 的示例代码。此代码的目标是设置一个角向上倾斜的立方体,以便识别相机的角度。它在PyGame中运行良好,但在PyQt5版本中存在几个问题:
首先,宽高比似乎不对。
其次,每次我再次激活它时,window 都会调用 paintGL。
第三,关于 glTranslatef 和 glRotatef,大多数变量的传输并不相同。
我为 PyGame 使用的代码:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 2),
(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)
)
colors = (
(1,0,0),
(0,1,0),
(0,0,1),
(0,1,0),
(1,1,1),
(0,1,1),
(1,0,0),
(0,1,0),
(0,0,1),
(1,0,0),
(1,1,1),
(0,1,1),
)
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)
)
def Cube():
glBegin(GL_QUADS)
for surface in surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0,0, -10) #these two lines set the camera facing at the cube from the position 0, -10, 0.
glRotatef(-90, 2, 0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
glTranslatef(-0.5,0,0)
if event.key == pygame.K_RIGHT:
glTranslatef(0.5,0,0)
if event.key == pygame.K_UP:
glTranslatef(0,1,0)
if event.key == pygame.K_DOWN:
glTranslatef(0,-1,0)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4:
glTranslatef(0,0,1.0)
if event.button == 5:
glTranslatef(0,0,-1.0)
#glRotatef(1, 3, 1, 1) #rotation code that was commented out.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
结果:
PyQt5代码:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.uic import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
class mainWindow(QMainWindow): #Main class.
verticies = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 2),
(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)
)
colors = (
(1,0,0),
(0,1,0),
(0,0,1),
(0,1,0),
(1,1,1),
(0,1,1),
(1,0,0),
(0,1,0),
(0,0,1),
(1,0,0),
(1,1,1),
(0,1,1),
)
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)
)
def __init__(self):
super(mainWindow, self).__init__()
self.width = 700 #Variables used for the setting of the size of everything
self.height = 600
self.setGeometry(0, 0, self.width, self.height) #Set the window size
def setupUI(self):
self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget
self.openGLWidget.setGeometry(0, 0, self.width, self.height) #Size it the same as the window.
self.openGLWidget.initializeGL()
self.openGLWidget.resizeGL(self.width, self.height) #Resize GL's knowledge of the window to match the physical size?
self.openGLWidget.paintGL = self.paintGL #override the default function with my own?
def paintGL(self):
gluPerspective(45, self.width / self.height, 0.1, 50.0) #set perspective?
glTranslatef(0, 0, -2) #I used -10 instead of -2 in the PyGame version.
glRotatef(-90, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) #Straight from the PyGame version, with 'self' inserted occasionally
glBegin(GL_QUADS) #tell GL to draw surfaces
for surface in self.surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(self.colors[x])
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing surfaces
glBegin(GL_LINES) #tell GL to draw lines
for edge in self.edges:
for vertex in edge:
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing lines.
app = QApplication([])
window = mainWindow()
window.setupUI()
window.show()
sys.exit(app.exec_())
结果:
当我切换到另一个 window,然后切换回 Qt window,场景更新并再次调用 paintGL。此外,立方体似乎被压扁了,相机的行为也有所不同。我该怎么做才能解决这些问题?
Python 3.8
Windows10
OpenGL 矩阵运算(如 gluPerspective
, glTranslate
, glRotate
、...)不只是设置矩阵。这些操作定义了一个新矩阵并将当前矩阵乘以新矩阵。每次调用paintGL
时矩阵连续递增变化的原因。
通过在 paintGL
::
开头的 glLoadIdentity
加载单位矩阵,可以轻松解决该问题
class mainWindow(QMainWindow):
# [...]
def paintGL(self):
glLoadIdentity()
gluPerspective(45, self.width / self.height, 0.1, 50.0) #set perspective?
glTranslatef(0, 0, -10) #I used -10 instead of -2 in the PyGame version.
glRotatef(-90, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
但是Legacy OpenGL provides different matrices (see glMatrixMode
).
建议将投影矩阵输出到当前GL_PROJECTION
矩阵,模型视图矩阵输出到当前GL_MODELVIEW
矩阵。
在调整大小事件回调 (resizeGL
) 中更新视口矩形 (glViewport
) 和投影矩阵。在paintGL
中设置模型视图矩阵:
class mainWindow(QMainWindow):
# [...]
def setupUI(self):
# [...]
self.openGLWidget.paintGL = self.paintGL
self.openGLWidget.resizeGL = self.resizeGL
def resizeGL(self, width, height):
self.width, self.height = width, height
# update viewport
glViewport(0, 0, self.width, self.height)
# set projection matrix
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, self.width / self.height, 0.1, 50.0) #set perspective?
def paintGL(self):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -10) #I used -10 instead of -2 in the PyGame version.
glRotatef(-90, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) #Straight from the PyGame version, with 'self' inserted occasionally
glBegin(GL_QUADS) #tell GL to draw surfaces
for surface in self.surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(self.colors[x])
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing surfaces
glBegin(GL_LINES) #tell GL to draw lines
for edge in self.edges:
for vertex in edge:
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing lines.
我正在尝试将 PyGame PyOpenGL tutorial 的示例代码拼凑成 PyQt5 QOpenGLWidget 的示例代码。此代码的目标是设置一个角向上倾斜的立方体,以便识别相机的角度。它在PyGame中运行良好,但在PyQt5版本中存在几个问题:
首先,宽高比似乎不对。 其次,每次我再次激活它时,window 都会调用 paintGL。 第三,关于 glTranslatef 和 glRotatef,大多数变量的传输并不相同。
我为 PyGame 使用的代码:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 2),
(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)
)
colors = (
(1,0,0),
(0,1,0),
(0,0,1),
(0,1,0),
(1,1,1),
(0,1,1),
(1,0,0),
(0,1,0),
(0,0,1),
(1,0,0),
(1,1,1),
(0,1,1),
)
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)
)
def Cube():
glBegin(GL_QUADS)
for surface in surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0,0, -10) #these two lines set the camera facing at the cube from the position 0, -10, 0.
glRotatef(-90, 2, 0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
glTranslatef(-0.5,0,0)
if event.key == pygame.K_RIGHT:
glTranslatef(0.5,0,0)
if event.key == pygame.K_UP:
glTranslatef(0,1,0)
if event.key == pygame.K_DOWN:
glTranslatef(0,-1,0)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4:
glTranslatef(0,0,1.0)
if event.button == 5:
glTranslatef(0,0,-1.0)
#glRotatef(1, 3, 1, 1) #rotation code that was commented out.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
结果:
PyQt5代码:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.uic import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
class mainWindow(QMainWindow): #Main class.
verticies = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 2),
(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)
)
colors = (
(1,0,0),
(0,1,0),
(0,0,1),
(0,1,0),
(1,1,1),
(0,1,1),
(1,0,0),
(0,1,0),
(0,0,1),
(1,0,0),
(1,1,1),
(0,1,1),
)
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)
)
def __init__(self):
super(mainWindow, self).__init__()
self.width = 700 #Variables used for the setting of the size of everything
self.height = 600
self.setGeometry(0, 0, self.width, self.height) #Set the window size
def setupUI(self):
self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget
self.openGLWidget.setGeometry(0, 0, self.width, self.height) #Size it the same as the window.
self.openGLWidget.initializeGL()
self.openGLWidget.resizeGL(self.width, self.height) #Resize GL's knowledge of the window to match the physical size?
self.openGLWidget.paintGL = self.paintGL #override the default function with my own?
def paintGL(self):
gluPerspective(45, self.width / self.height, 0.1, 50.0) #set perspective?
glTranslatef(0, 0, -2) #I used -10 instead of -2 in the PyGame version.
glRotatef(-90, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) #Straight from the PyGame version, with 'self' inserted occasionally
glBegin(GL_QUADS) #tell GL to draw surfaces
for surface in self.surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(self.colors[x])
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing surfaces
glBegin(GL_LINES) #tell GL to draw lines
for edge in self.edges:
for vertex in edge:
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing lines.
app = QApplication([])
window = mainWindow()
window.setupUI()
window.show()
sys.exit(app.exec_())
结果:
当我切换到另一个 window,然后切换回 Qt window,场景更新并再次调用 paintGL。此外,立方体似乎被压扁了,相机的行为也有所不同。我该怎么做才能解决这些问题?
Python 3.8 Windows10
OpenGL 矩阵运算(如 gluPerspective
, glTranslate
, glRotate
、...)不只是设置矩阵。这些操作定义了一个新矩阵并将当前矩阵乘以新矩阵。每次调用paintGL
时矩阵连续递增变化的原因。
通过在 paintGL
::
glLoadIdentity
加载单位矩阵,可以轻松解决该问题
class mainWindow(QMainWindow):
# [...]
def paintGL(self):
glLoadIdentity()
gluPerspective(45, self.width / self.height, 0.1, 50.0) #set perspective?
glTranslatef(0, 0, -10) #I used -10 instead of -2 in the PyGame version.
glRotatef(-90, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
但是Legacy OpenGL provides different matrices (see glMatrixMode
).
建议将投影矩阵输出到当前GL_PROJECTION
矩阵,模型视图矩阵输出到当前GL_MODELVIEW
矩阵。
在调整大小事件回调 (resizeGL
) 中更新视口矩形 (glViewport
) 和投影矩阵。在paintGL
中设置模型视图矩阵:
class mainWindow(QMainWindow):
# [...]
def setupUI(self):
# [...]
self.openGLWidget.paintGL = self.paintGL
self.openGLWidget.resizeGL = self.resizeGL
def resizeGL(self, width, height):
self.width, self.height = width, height
# update viewport
glViewport(0, 0, self.width, self.height)
# set projection matrix
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, self.width / self.height, 0.1, 50.0) #set perspective?
def paintGL(self):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -10) #I used -10 instead of -2 in the PyGame version.
glRotatef(-90, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) #Straight from the PyGame version, with 'self' inserted occasionally
glBegin(GL_QUADS) #tell GL to draw surfaces
for surface in self.surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(self.colors[x])
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing surfaces
glBegin(GL_LINES) #tell GL to draw lines
for edge in self.edges:
for vertex in edge:
glVertex3fv(self.verticies[vertex])
glEnd() #tell GL to stop drawing lines.