将PyOpenGL从PyGame传输到PyQt5时的混乱

2024-09-26 18:10:51 发布

您现在位置:Python中文网/ 问答频道 /正文

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

首先,纵横比似乎是关闭的。 第二,每次我再次激活该窗口时,它都会调用paintGL。 第三,大多数变量在GLTRANSTALEF和GLROTATIEF方面的传递方式不同

我用于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()

结果是: PyGame version of the cube

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

结果是:

PyQt5 version of the cube

当我切换到另一个窗口,然后切换回Qt窗口时,场景将更新,并再次调用paintGL。此外,立方体似乎被挤压,相机的动作也不同。我能做些什么来修复这些

Python 3.8 视窗10


Tags: theinfromimportselfeventforif
1条回答
网友
1楼 · 发布于 2024-09-26 18:10:51

OpenGL矩阵操作(如^{}^{}^{}、…)不仅仅设置矩阵。这些操作定义一个新矩阵,并将当前矩阵乘以新矩阵。每次调用paintGL时,矩阵持续且渐进变化的原因。
通过在paintGL开头的^{}加载标识矩阵,可以轻松解决该问题:

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提供了不同的矩阵(参见^{})。
建议将投影矩阵推到当前GL_PROJECTION矩阵,将模型视图矩阵推到当前GL_MODELVIEW矩阵。
在调整大小事件回调(resizeGL)中更新视口矩形(^{})和投影矩阵。在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.

相关问题 更多 >

    热门问题