为啥当我没有为我的 openGLWidget 创建额外的类时 glRotate 只工作一次?

Posted

技术标签:

【中文标题】为啥当我没有为我的 openGLWidget 创建额外的类时 glRotate 只工作一次?【英文标题】:Why does glRotate work only once when I don't create an extra class for my openGLWidget?为什么当我没有为我的 openGLWidget 创建额外的类时 glRotate 只工作一次? 【发布时间】:2019-10-11 18:52:10 【问题描述】:

我正在编写一个 GUI,用于使用 Python 显示 6 轴运动传感器的输出。 Window 应该有一个实时显示旋转的 OpenGL Widget。通常我会为我的openGLWidget 编写一个单独的类,但由于我的 UI 有很多元素,因此从头开始构建它似乎不合理。相反,我只是加载 .ui 文件,找到我需要的一切,仅此而已。但是,glRotate() 函数只更新了一次,然后就再也不会更新了,我不知道是什么导致了这个问题。

from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import *
import OpenGL.GL as gl
import OpenGL.GLU as glu
import sys


class Ui(QtWidgets.QWidget):
    def __init__(self):
        super(Ui, self).__init__()
        uic.loadUi('gl_test.ui', self)

        self.openGLWidget = self.findChild(QtWidgets.QOpenGLWidget, 'openGLWidget')
        self.openGLWidget.initializeGL()
        self.openGLWidget.paintGL = self.paintGL
        self.openGLWidget.initializeGL = self.initializeGL
        self.object = None

        self.rotation = 45.0

#       QTimer for updating the GL Viewport
        self.GLtimer = QTimer()
        self.GLtimer.setInterval(100)
        self.GLtimer.timeout.connect(self.openGLWidget.paintGL)
        self.GLtimer.start()

    def paintGL(self):
        try:
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            gl.glMatrixMode(gl.GL_PROJECTION)
            gl.glLoadIdentity()
            x, y, width, height = gl.glGetDoublev(gl.GL_VIEWPORT)
            glu.gluPerspective(
                45,  # field of view in degrees
                width / float(height or 1),  # aspect ratio
                .25,  # near clipping plane
                200,  # far clipping plane
            )
            gl.glMatrixMode(gl.GL_MODELVIEW)
            gl.glLoadIdentity()
            gl.glTranslated(0.0, 0.0, -10.0)
            self.rotation += 1
            print(self.rotation)
            gl.glRotate(self.rotation, 1, 0, 0)  # works only once for some reason?
            gl.glCallList(self.object)
        except Exception as exc:
            print(exc)
            pass

    def initializeGL(self):
        try:
            # making an example cube
            self.object = gl.glGenLists(1)
            gl.glNewList(self.object, gl.GL_COMPILE)
            gl.glBegin(gl.GL_QUADS)

            gl.glColor3f(0.0, 1.0, 0.0)
            gl.glVertex3f(1.0, 1.0, -1.0)
            gl.glVertex3f(-1.0, 1.0, -1.0)
            gl.glVertex3f(-1.0, 1.0, 1.0)
            gl.glVertex3f(1.0, 1.0, 1.0)

            gl.glColor3f(0.0, 1.0, 0.0)
            gl.glVertex3f(1.0, -1.0, 1.0)
            gl.glVertex3f(-1.0, -1.0, 1.0)
            gl.glVertex3f(-1.0, -1.0, -1.0)
            gl.glVertex3f(1.0, -1.0, -1.0)

            gl.glColor3f(0.0, 1.0, 0.0)
            gl.glVertex3f(1.0, 1.0, 1.0)
            gl.glVertex3f(-1.0, 1.0, 1.0)
            gl.glVertex3f(-1.0, -1.0, 1.0)
            gl.glVertex3f(1.0, -1.0, 1.0)

            gl.glColor3f(0.0, 1.0, 0.0)
            gl.glVertex3f(1.0, -1.0, -1.0)
            gl.glVertex3f(-1.0, -1.0, -1.0)
            gl.glVertex3f(-1.0, 1.0, -1.0)
            gl.glVertex3f(1.0, 1.0, -1.0)

            gl.glColor3f(0.0, 1.0, 0.0)
            gl.glVertex3f(-1.0, 1.0, 1.0)
            gl.glVertex3f(-1.0, 1.0, -1.0)
            gl.glVertex3f(-1.0, -1.0, -1.0)
            gl.glVertex3f(-1.0, -1.0, 1.0)

            gl.glColor3f(0.0, 1.0, 0.0)
            gl.glVertex3f(1.0, 1.0, -1.0)
            gl.glVertex3f(1.0, 1.0, 1.0)
            gl.glVertex3f(1.0, -1.0, 1.0)
            gl.glVertex3f(1.0, -1.0, -1.0)

            gl.glEnd()
            gl.glEndList()

            gl.glEnable(gl.GL_CULL_FACE)
        except Exception as exc:
            print(exc)
            pass


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = Ui()
    window.show()
    app.exec_()


main()

.ui file code

这是不起作用的部分。随着 self.rotation 每次增加 paintGl() 并因此 glRotate() 被调用,我希望 Cube 旋转,但由于某种原因它不会旋转。

【问题讨论】:

【参考方案1】:

问题是定时器事件:

self.GLtimer.timeout.connect(self.openGLWidget.paintGL)

不建议直接拨打.paintGL。请注意,OpenGL 不能绘制任何东西,OpenGL Context 必须在绘制之前和之后变为当前状态,必须更新窗口。您可以看到初始绘图,因为对.paintGL 的第一次调用是由框架完成的。以下由计时器事件发起的调用不会生成有效输出。 您必须调用 .update(),这会使上下文成为当前上下文并触发 .paintGL() 被调用,例如:

class Ui(QtWidgets.QWidget):
    def __init__(self):

        # [...]

        self.GLtimer = QTimer()
        self.GLtimer.setInterval(100)
        self.GLtimer.timeout.connect(self.redraw) 
        self.GLtimer.start()

    def redraw(self):
        # updated the widget - triggers paintGL to be called
        self.openGLWidget.update()

动画是由你的原始代码生成的,只是我已经通过glPolygonMode切换到画线模式。

gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)

【讨论】:

以上是关于为啥当我没有为我的 openGLWidget 创建额外的类时 glRotate 只工作一次?的主要内容,如果未能解决你的问题,请参考以下文章

当我将条目插入现有部分时,为啥我的 UITableView 会为我添加另一个部分?

为啥当我单击一个链接时,它会为我的所有链接执行该功能? (Javascipt)

为啥 Mockery 无法为我的模型创建别名

为啥我的 Chrome Profiler 没有为我的对象显示正确的保留路径,为啥我的对象从未被释放?

当我构建我的项目时,Visual Studio 2008 没有创建 .exe 文件。任何想法为啥?

为啥我的显式构造函数会为我的转换运算符创建这种歧义?