简体   繁体   English

将 PyOpenGL 从 PyGame 转移到 PyQt5 的困惑

[英]Confusion transferring PyOpenGL from PyGame to PyQt5

I am trying to piece example code for a PyGame PyOpenGL tutorial into example code for a PyQt5 QOpenGLWidget.我正在尝试将PyGame PyOpenGL 教程的示例代码拼凑成 PyQt5 QOpenGLWidget 的示例代码。 The goal of this code is to set up a cube with one corner skewed upward in order to identify the angle of the camera.这段代码的目标是建立一个角向上倾斜的立方体,以识别相机的角度。 It works fine in PyGame, but there are several problems with the PyQt5 version:在 PyGame 中运行良好,但是 PyQt5 版本存在几个问题:

First, the aspect ratio seems to be off.首先,纵横比似乎是关闭的。 Second, the window recalls paintGL every time I make it active again.其次,每次我再次激活它时,窗口都会调用paintGL。 Third, most of the variables are not transferring the same in regards to glTranslatef and glRotatef.第三,对于 glTranslatef 和 glRotatef,大多数变量的传递方式不同。

The code I am using for PyGame:我用于 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()

The result:结果: PyGame 版本的立方体

The PyQt5 code: 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_())

The result:结果:

PyQt5 版本的立方体

When I switch to another window, then switch back to the Qt window, the scene updates and paintGL is called again.当我切换到另一个窗口,然后切换回 Qt 窗口时,场景更新并再次调用paintGL。 Also, the cube appears to be squashed and the camera acts differently.此外,立方体似乎被压扁了,相机的行为也有所不同。 What can I do to fix these?我能做些什么来解决这些问题?

Python 3.8 Windows 10 Python 3.8 视窗 10

The OpenGL matrix operations (like gluPerspective , glTranslate , glRotate , ...) do not just set a matrix. OpenGL 矩阵操作(如gluPerspectiveglTranslateglRotate等)不只是设置矩阵。 The operations define a new matrix and multiply the current matrix by the new matrix.这些操作定义了一个新矩阵并将当前矩阵乘以新矩阵。 The causes that the matrix continuously and progressively changes, every time when paintGL is called.每次调用paintGL时,矩阵连续渐进变化的原因。
The issue can be solved with ease, by loading the identity matrix by glLoadIdentity at the begin of paintGL ::这个问题可以轻松解决,通过加载单位矩阵glLoadIdentity在开始的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.

But Legacy OpenGL provides different matrices (see glMatrixMode ).但是Legacy OpenGL提供了不同的矩阵(请参阅glMatrixMode )。
It is recommend to pout the projection matrix to the current GL_PROJECTION matrix and the model view matrix to the current GL_MODELVIEW matrix.建议将投影矩阵GL_PROJECTION到当前GL_PROJECTION矩阵,将模型视图矩阵GL_MODELVIEW到当前GL_MODELVIEW矩阵。
Update the viewport rectangle ( glViewport ) and the projection matrix in the resize event callback ( resizeGL ).在调整大小事件回调 ( resizeGL ) 中更新视口矩形 ( glViewport ) 和投影矩阵。 Set the model view matrix in paintGL :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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM