系列文章
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渲染器照片级渲染效果