Python+OpenGL绘制3D模型(三)程序框架PyQt6

本文探讨了如何通过逆向工程深入理解Sketchup的底层数据结构,以及使用Python和PyQt构建OpenGL渲染3D模型的教程,包括OpenGL环境设置、3D模型绘制和Sketchup文件解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系列文章

Python+OpenGL绘制3D模型(一)Python 和 PyQt环境搭建
Python+OpenGL绘制3D模型(二)程序框架PyQt5
Python+OpenGL绘制3D模型(三)程序框架PyQt6
Python+OpenGL绘制3D模型(四)绘制线段
Python+OpenGL绘制3D模型(五)绘制三角型
Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射
Python+OpenGL绘制3D模型(七)制作3dsmax导出插件
Python+OpenGL 杂谈(一)

前言

Sketchup作为目前设计院最为流行的设计软件(非工程制图软件),深受设计师的喜爱,软件小巧,而功能强大,有不少为之开发的插件应运而生,不过呢,关于底层数据结构和工作原理相关的文章少之又少,本文意在填补一下这方面的空缺,通过逆向软件分析,展示软件内部奥秘。本文用到的工具:IDA Pro,Immunity Debugger,Visual Studio (逆向工程三件套)数据结构属于知识产权的核心机密:


PyQt6 和 PyQt5 的区别

PyQt6和PyQt5的主要区别在初始化OpenGL环境,其他所有用到的OpenGL函数都是通用的,还是比较容易迁移代码

PyQt5:

def initializeGL(self):
    version_profile = QOpenGLVersionProfile()
    version_profile.setVersion(2, 0)
    self.gl = self.context().versionFunctions(version_profile)
    self.gl.initializeOpenGLFunctions()

PyQt6:

def initializeGL(self):
    context = self.context()
    version_profile = QOpenGLVersionProfile()
    version_profile.setVersion(2, 0)
    self.gl = QOpenGLVersionFunctionsFactory.get(version_profile, context)

源代码:

import sys
from PyQt6.QtCore import (QPoint)
from PyQt6.QtGui import (QMatrix4x4, QVector3D)
from PyQt6.QtOpenGL import QOpenGLVersionProfile
from PyQt6.QtWidgets import QApplication
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from PyQt6.QtOpenGL import QOpenGLVersionFunctionsFactory

################################
#              FILE DESCRIPTION
#  文件描述:GLWidget
#  对应文章:Python+OpenGL绘制3D模型(三)程序框架PyQt6
#  作者:李航 Lihang
#   1、创建OpenGL环境
#   2、设置矩阵
#   3、控制窗口视角
#   4、调用 draw 绘图主函数
################################
class GLWidget(QOpenGLWidget):
    def __init__(self, parent):
        super(GLWidget, self).__init__( parent)
        self.dragPressPos = QPoint()
        self.rotX=45
        self.rotZ=0
        self.ps_button = 0
        self.ps_rotX = 0
        self.ps_rotZ = 0
        self.zoom=10

    #--------------------
    # 创建OpenGL环境
    # Qt6 和 Qt5的主要区别在这里
    #--------------------
    def initializeGL(self):
        context = self.context()
        version_profile = QOpenGLVersionProfile()
        version_profile.setVersion(2, 0)
        self.gl = QOpenGLVersionFunctionsFactory.get(version_profile, context)

    #--------------------
    # paintEvent
    #--------------------
    def paintEvent(self,  event):
        # Step 0
        self.makeCurrent()

        # Step 1
        self.gl.glClearColor(0.85, 0.85, 0.85, 1.0)
        self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT)
        self.gl.glEnable(self.gl.GL_DEPTH_TEST)
        
        # Step 2
        self.SetupMatrix()
        
        # Step 3
        self.drawTarget(self.gl)

    #--------------------
    # 绘图
    # 这里是个绘图的简单测试代码
    #--------------------
    def drawTarget(self, gl):
        p = QVector3D(0, 0, 0)
        
        gl.glColor3f(1.0, 0.0, 0.0);
        gl.glBegin(gl.GL_LINES)
        gl.glVertex3d(p.x()-1,  p.y(),  p.z()  )
        gl.glVertex3d(p.x()+1,  p.y(),  p.z() )
        gl.glEnd()
        
        gl.glColor3f(0.0, 1.0, 0.0);
        gl.glBegin(gl.GL_LINES)
        gl.glVertex3d(p.x(),  p.y()-1,  p.z()  )
        gl.glVertex3d(p.x(),  p.y()+1,  p.z() )
        gl.glEnd()
        
        gl.glColor3f(0.0, 0.0, 1.0);
        gl.glBegin(gl.GL_LINES)
        gl.glVertex3d(p.x(),  p.y(),  p.z()  )
        gl.glVertex3d(p.x(),  p.y(),  p.z() +4 )
        gl.glEnd()

    #--------------------
    # 设置矩阵
    # 1、Viewport
    # 2、透视矩阵
    # 3、Camera矩阵
    #--------------------
    def SetupMatrix(self):
        # ViewPort
        w = self.width()
        h = self.height()
        self.gl.glViewport(0, 0, w, h)  
        
        # Projection
        self.gl.glMatrixMode(self.gl.GL_PROJECTION)
        pm = QMatrix4x4()
        aspectRatio = w/h
        fov = 45 / aspectRatio if w < h else 45
        pm.perspective(fov,  w/h,  2,  5000)
        self.gl.glLoadMatrixf(pm.data())
        
        # Camera
        self.gl.glMatrixMode(self.gl.GL_MODELVIEW)
        self.gl.glLoadIdentity()
        
        self.gl.glTranslatef(0.0,0.0,-self.zoom)
        self.gl.glRotatef(self.rotX-90,1.0,0.0,0.0)
        self.gl.glRotatef(self.rotZ,0.0,0.0,1.0)
        
    #--------------------
    # 视角控制
    # 1、左键旋转
    # 2、中间缩放
    # 3、平移 **TODO**
    #--------------------
    def mousePressEvent(self,event):
        self.dragPressPos = event.pos()
        
        self.ps_button = event.button().value
        self.ps_rotX = self.rotX
        self.ps_rotZ = self.rotZ
        
    def mouseMoveEvent(self, event):
        diff = event.pos() - self.dragPressPos
        if self.ps_button == 1:
            self.rotX = self.ps_rotX + diff.y()*0.5
            if self.rotX > 90:
                self.rotX = 90
            if self.rotX < -90:
                self.rotX = -90;            
            # rotZ
            self.rotZ = self.ps_rotZ + diff.x()*0.5

        self.repaint()

    def wheelEvent(self, event):
        delta = event.angleDelta().y()

        if delta < 0 :
            self.zoom += self.zoom * 0.2
        else:
            self.zoom -= self.zoom * 0.2
        
        self.repaint()

#--------------------
# App
# 创建主窗口应用程序
# 并且进入消息循环
#--------------------
if __name__ == '__main__':
    app = QApplication(sys.argv)
    widget = GLWidget(None)
    widget.resize(640, 480)
    widget.show()
    sys.exit(app.exec())

运行指令

运行程序很方便,以上代码复制下来保存成tOpenGL.py,直接用python运行,可以得到一个很简单的OpenGL窗口

python tOpenGL.py

在这里插入图片描述

系列文章预告

目标是一个完善的Viewer,能够显示Sketchup的.skp文件中的3D模型
在这里插入图片描述

Corona渲染器照片级渲染效果
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值