【问题标题】:Confusion transferring PyOpenGL from PyGame to PyQt5将 PyOpenGL 从 PyGame 转移到 PyQt5 的困惑
【发布时间】:2020-02-15 14:22:29
【问题描述】:

我正在尝试将PyGame PyOpenGL tutorial 的示例代码拼凑成 PyQt5 QOpenGLWidget 的示例代码。此代码的目标是设置一个角向上倾斜的立方体,以识别相机的角度。在 PyGame 中运行良好,但 PyQt5 版本存在几个问题:

首先,纵横比似乎关闭了。 其次,每次我再次激活它时,窗口都会调用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_())

结果:

当我切换到另一个窗口,然后切换回 Qt 窗口时,场景更新并再次调用paintGL。此外,立方体似乎被压扁了,相机的动作也有所不同。我能做些什么来解决这些问题?

Python 3.8 视窗 10

【问题讨论】:

    标签: python opengl pygame pyqt5 opengl-compat


    【解决方案1】:

    OpenGL 矩阵运算(如gluPerspectiveglTranslateglRotate、...)不只是设置矩阵。这些操作定义了一个新矩阵并将当前矩阵乘以新矩阵。每次调用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 提供了不同的矩阵(参见glMatrixMode)。
    建议将投影矩阵pout到当前GL_PROJECTION矩阵,将模型视图矩阵pout到当前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.
    

    【讨论】:

    • 我实现了 glLoadIdentity 函数并将 glTranslate 调回 -10。解决了我所有的问题!我对这个问题的解决如此容易感到震惊。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2020-12-23
    • 2013-08-09
    • 1970-01-01
    • 2019-06-14
    • 2017-04-18
    • 1970-01-01
    相关资源
    最近更新 更多