使用openGL绘制图形显示在pyqt建立的ui界面中

使用openGL绘制图形显示在pyqt建立的ui界面中,一种方法是使用widget对象,将widget提升成自定义成openglwidget显示openGL的图像。

1.安装pyqt、qtdesigner.exe、pyuic.exe工具。
qtdesigner.exe可以像QT的IDE一样,拖拽生成操作界面(所见即所得的界面生成工具)。
pyuic.exe可以把界面的.ui文件转化为py文件。

安装 pyQt5 和 pyQt5-tool, 直接使用 pip 或者 conda 安装就行. 设置好pycharm中的 external tool。参考博客1。
博客1:https://blog.csdn.net/qq_42980303/article/details/87869884

在博客1中提供的路径,安装后可能找不到 designer.exe 文件。
我用的是Anaconda, 是在E:\Anaconda\envs\py_tensorflow_keras\Library\bin路径下找到的。还是找不到的话,参考博客2和博客2.1。
博客2:https://blog.csdn.net/sinat_21427221/article/details/77448857
博客2.1:https://blog.csdn.net/qqwangfan/article/details/114290781

同样的方法安装一下 PYUIC.exe。参考博客1。
我使用的路径是E:\Anaconda\envs\py_tensorflow_keras\python.exe

2.安装openGL。
我使用的版本是py-3.7,直接使用conda或pip安装的openGL使用有问题,无法正常运行。所以使用.whl文件进行安装。
安装文件是 PyOpenGL-3.1.5-cp37-cp37m-win_amd64.whl
还有一个加速包 PyOpenGL_accelerate-3.1.5-cp37-cp37m-win_amd64.whl
下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl

3.使用qtdesigner.exe图形化界面设计。
参考博客3可以进行ui设计。直接使用参考的代码, 可能会出现 AttributeError: ‘MyPyQT_Form’ object has no attribute ‘setCentralWidget’ 的错误。解决方法是继承时使用 QtWidgets.QMainWindow 代替 QtWidgets.QWidget 。参考博客4。
博客3:https://www.cnblogs.com/lsdb/p/9122425.html
博客4:https://blog.csdn.net/wardenjohn/article/details/87628891

4.qt设计的ui中显示openGL图形。
ui中显示openGL图形需要使用widget对象,将widget提升成自定义成openglwidget显示openGL的图像。参考博客5。
博客5:https://www.cxyzjd.com/article/qq_39694792/111719618

5.示例。
设计界面如图:
在这里插入图片描述
对于按键QPushButton,无法像QT一样直接转到槽,而是需要自行设置。
首先需要添加槽函数。
在这里插入图片描述

绑定槽函数和信号。
在这里插入图片描述
设置好发送接收和触发方式,在MainWindows类中定义槽函数即可。

对于显示对象QTextEdit,直接使用即可。

import sys
from PyQt5 import QtWidgets, QtOpenGL
from Ui_design import Ui_MainWindow


# 这里需要用继承的方法. 因为生成的文件可能会因为界面而改变, 直接继承就不用担心代码被覆盖.
class MyPyQT_Form(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyPyQT_Form, self).__init__(parent=parent)
        self.setupUi(self)      # 这个是继承.ui文件的类里面来的.

    #实现pushButton_click()函数,textEdit是我们放上去的文本框的id
    def pushButton_display_click(self):
        self.textEdit_display.setText("你点击了按钮")

    def pushButton_clear_click(self):
        self.textEdit_display.clear()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = MyPyQT_Form()
    w.show()
    sys.exit(app.exec_())

参考博客5的方式,将widget对象提升。
右键选择“提升为…”,填写 提升类的对象 和 头文件 即可(任意填写),添加即可。
在这里插入图片描述

显示效果:
在这里插入图片描述
在生成头文件opengl_widget.py中,继承QOpenGLWidget。参考博客5(openGL部分代码是直接赋值粘贴过来的)。
此处需要注意,继承的类中有三个虚函数,需要重写。
参考文档:
https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QOpenGLWidget.html

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

from PyQt5 import QtCore, QtGui, QtWidgets, QtOpenGL

class openGL_Widget(QtWidgets.QOpenGLWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        # 这个三个是虚函数, 需要重写
        # paintGL
        # initializeGL
        # resizeGL

    # 启动时会先调用 initializeGL, 再调用 resizeGL , 最后调用两次 paintGL
    # 出现窗口覆盖等情况时, 会自动调用 paintGL
    # 调用过程参考 https://segmentfault.com/a/1190000002403921
    # 绘图之前的设置
    def initializeGL(self):
        glClearColor(0, 0, 0, 1)
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_LIGHT0)
        glEnable(GL_LIGHTING)
        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)

	# 绘图函数
    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glBegin(GL_TRIANGLES)
        glColor3f(1.0, 0.0, 0.0)
        glVertex3f(-0.5, -0.5, 0)
        glColor3f(0.0, 1.0, 0.0)
        glVertex3f(0.5, -0.5, 0)
        glColor3f(0.0, 0.0, 1.0)
        glVertex3f(0.0, 0.5, 0)

        glEnd()

    def resizeGL(self, w, h):
        glViewport(0, 0, w, h)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, w / h, 0.01, 100.0)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0)

附上ui转换得到的py文件。
这个文件是PyUIC转换得到的,每次修改.ui绘图时都需要重新生成。所以不建议修改此文件,继承使用即可。

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(946, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton_display = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_display.setGeometry(QtCore.QRect(10, 270, 91, 31))
        self.pushButton_display.setObjectName("pushButton_display")
        self.pushButton_clear = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_clear.setGeometry(QtCore.QRect(120, 270, 91, 31))
        self.pushButton_clear.setObjectName("pushButton_clear")
        self.textEdit_display = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit_display.setGeometry(QtCore.QRect(10, 80, 241, 181))
        self.textEdit_display.setObjectName("textEdit_display")
        self.widget = openGL_Widget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(270, 10, 640, 511))
        self.widget.setObjectName("widget")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 946, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.pushButton_display.clicked.connect(MainWindow.pushButton_display_click)
        self.pushButton_clear.clicked.connect(MainWindow.pushButton_clear_click)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_display.setText(_translate("MainWindow", "显示"))
        self.pushButton_clear.setText(_translate("MainWindow", "清除"))
from opengl_widget import openGL_Widget

最终的显示效果:
在这里插入图片描述
补充一点(代码中也有注释):
在py程序启动时会先调用 initializeGL, 再调用 resizeGL , 最后调用两次 paintGL;出现窗口覆盖等情况时, 会自动调用 paintGL;出现窗口大小变换时会调用resizeGL。
参考博客: https://segmentfault.com/a/1190000002403921

上述方式是被动刷新,是需要对窗口的操作才会调用paintGL进行更新图像。如果需要主动刷新图像,可以使用widget.update()方法,本质上也是调用paintGL进行更新图像。
例如在最开始的代码中,在希望按下按键时刷新图像,可以写为:

    def pushButton_display_click(self):
        self.textEdit_display.setText("你点击了按钮")
        self.widget.update()	# 刷新图像
### 回答1: 可以使用PyOpenGL库来实现这个功能,具体的实现方法可以参考以下代码: ```python from PyQt5.QtWidgets import * from PyQt5.QtOpenGL import * from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * import sys class GLWidget(QOpenGLWidget): def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 def initializeGL(self): self.qglClearColor(Qt.black) self.object = self.makeObject() def resizeGL(self, width, height): side = min(width, height) glViewport((width - side) // 2, (height - side) // 2, side, side) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) glMatrixMode(GL_MODELVIEW) def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslated(0.0, 0.0, -10.0) glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) glCallList(self.object) def makeObject(self): list = glGenLists(1) glNewList(list, GL_COMPILE) # Load the obj file here glEndList() return list def setXRotation(self, angle): self.xRot = angle self.update() def setYRotation(self, angle): self.yRot = angle self.update() def setZRotation(self, angle): self.zRot = angle self.update() def sizeHint(self): return QSize(640, 480) if __name__ == '__main__': app = QApplication(sys.argv) widget = GLWidget() widget.show() sys.exit(app.exec_()) ``` 这段代码实现了一个基本的OpenGL窗口,并且可以通过makeObject函数来加载obj模型。你可以在这个函数使用PyOpenGL提供的函数来加载obj文件,然后将其渲染到窗口。 ### 回答2: PyQt使用OpenGLWidget导入OBJ模型需要以下步骤: 1. 首先,确保已经安装了PyQt和PyOpenGL库,可以使用pip命令进行安装: ```python pip install PyQt5 pip install PyOpenGL ``` 2. 在PyQt应用程序创建一个OpenGLWidget对象: ```python from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget from PyQt5.QtOpenGL import QGLWidget class MyGLWidget(QGLWidget): def __init__(self, parent=None): super(MyGLWidget, self).__init__(parent) def initializeGL(self): # 在这里进行OpenGL的初始化操作 pass def paintGL(self): # 在这里进行OpenGL的渲染操作 pass def resizeGL(self, width, height): # 在这里处理窗口大小变化时的逻辑 pass ``` 3. 在OpenGLWidget的`initializeGL`方法,加载和解析OBJ模型文件: ```python def initializeGL(self): # 加载OBJ模型文件 with open('model.obj', 'r') as f: lines = f.readlines() vertices = [] normals = [] for line in lines: if line.startswith('v '): # 处理顶点坐标 vertex = [float(coord) for coord in line.split()[1:]] vertices.append(vertex) elif line.startswith('vn '): # 处理法线坐标 normal = [float(coord) for coord in line.split()[1:]] normals.append(normal) # 将解析的模型数据传递给OpenGL进行渲染 # ... ``` 4. 在OpenGLWidget的`paintGL`方法使用解析的模型数据进行渲染: ```python def paintGL(self): # 清空画布 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 设置相机参数 glLoadIdentity() # ... # 渲染OBJ模型 glBegin(GL_TRIANGLES) for vertex, normal in zip(vertices, normals): glNormal3f(*normal) # 设置法线坐标 glVertex3f(*vertex) # 设置顶点坐标 glEnd() # 刷新画布 glFlush() ``` 5. 最后,在应用程序创建一个窗口并将OpenGLWidget添加到布局: ```python app = QApplication(sys.argv) window = QWidget() layout = QVBoxLayout() gl_widget = MyGLWidget() layout.addWidget(gl_widget) window.setLayout(layout) window.show() sys.exit(app.exec_()) ``` 通过以上步骤,我们可以在PyQt应用程序使用OpenGLWidget导入和渲染OBJ模型。当然,具体的渲染逻辑可能需要根据项目需求进行调整。 ### 回答3: pyqt是一种Python编程语言的图形用户界面工具包,可以与其他功能库集成,其包括OpenGLWidget用于创建和展示3D图形。而导入obj模型是指将.obj文件作为3D模型的输入,并将其加载到OpenGLWidget窗口进行展示。 要使用pyqtOpenGLWidget导入obj模型,首先需要安装pyqt并加载OpenGLWidget模块。可以通过pip安装PyQt5库,或者在Python环境安装相应的包。 接下来,需要加载.obj文件的内容。可以使用Python的模型加载库(如PyOpenGL或Assimp)来加载.obj文件。这些库允许你从文件读取顶点、法线、纹理等模型数据,并将其转化为OpenGL可用的格式。 在加载模型之后,需要使用OpenGL函数或者OpenGL扩展来渲染这些模型。OpenGL提供了用于设置光线、材质、纹理等属性的函数,并且可以通过glBegin和glEnd之间的代码块来定义几何形状。可以通过读取模型的顶点、法线和纹理坐标等数据来渲染obj模型。 最后,将渲染的结果传递给OpenGLWidget窗口来进行展示。可以使用OpenGLWidget的paintGL函数来执行实际的渲染操作,并将结果显示pyqt的窗口。 综上所述,使用pyqtOpenGLWidget导入obj模型的过程包括安装pyqt、加载obj文件、渲染模型以及将渲染结果显示pyqt窗口
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值