PyQt6-3D应用开发技术文档
1. 概述
1.1 PyQt6-3D简介
PyQt6是Python语言的Qt6框架绑定,提供了丰富的GUI开发工具。其中,PyQt6-3D模块为开发3D应用程序提供了强大支持,允许开发者创建交互式3D场景、模型和动画。通过PyQt6-3D,开发者可以将3D功能集成到桌面应用、教育软件、医学可视化工具、建筑设计等多种领域。
1.2 应用场景
PyQt6-3D的应用场景非常广泛,主要包括但不限于以下领域:
- 医学可视化:3D医学影像展示与分析
- 建筑与室内设计:3D模型展示与交互
- 教育培训:虚拟实验与教学模拟
- 机器人路径规划:环境建模与路径仿真
- 产品虚拟装配与维修训练
- 地理信息系统:3D地形与城市建模
- 游戏开发辅助工具
1.3 开发环境准备
在开始使用PyQt6-3D开发前,需要安装相应的库:
bash
pip install PyQt6 PyOpenGL numpy
本文中的代码示例还可能使用到其他库,如Open3D用于模型加载,可根据需要安装:
bash
pip install open3d
2. 基础图形与交互
2.1 简单3D图形绘制:立方体的呈现
2.1.1 代码实现
python
import sys
from PyQt6.QtWidgets import QApplication, QWidget
from PyQt6.QtGui import QPainter, QColor
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from OpenGL.GL import *
from OpenGL.GLU import *
class CubeWidget(QOpenGLWidget):
def initializeGL(self):
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)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glBegin(GL_QUADS)
# 前面
glColor3f(1.0, 0.0, 0.0) # 红色
glVertex3f(-0.5, -0.5, 0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
# 后面
glColor3f(0.0, 1.0, 0.0) # 绿色
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(0.5, 0.5, -0.5)
glVertex3f(0.5, -0.5, -0.5)
# 上面
glColor3f(0.0, 0.0, 1.0) # 蓝色
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, -0.5)
# 下面
glColor3f(1.0, 1.0, 0.0) # 黄色
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(-0.5, -0.5, 0.5)
# 左面
glColor3f(1.0, 0.0, 1.0) # 品红色
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5, -0.5, 0.5)
# 右面
glColor3f(0.0, 1.0, 1.0) # 青色
glVertex3f(0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, -0.5)
glEnd()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(w) / float(h), 0.1, 100.0)
if __name__ == '__main__':
app = QApplication(sys.argv)
cube_widget = CubeWidget()
cube_widget.show()
sys.exit(app.exec())
2.1.2 代码解析
这段代码实现了一个基本的3D立方体渲染。主要包含三个核心方法:
- initializeGL():初始化OpenGL环境,启用深度测试、光照和材质处理。
- paintGL() :绘制3D场景,使用
glBegin(GL_QUADS)
和glEnd()
定义立方体的六个面,每个面设置不同颜色。 - resizeGL():处理窗口大小变化,设置透视投影矩阵。
2.1.3 技术要点
- 深度测试 :通过
glEnable(GL_DEPTH_TEST)
启用深度测试,确保3D物体正确显示前后关系。 - 光照模型 :使用
glEnable(GL_LIGHT0)
和glEnable(GL_LIGHTING)
启用光照效果,使立方体有明暗变化。 - 坐标系统:OpenGL使用右手坐标系,x轴向右,y轴向上,z轴向外。
2.2 3D场景导航控制:自由视角探索
2.2.1 代码实现
python
import sys
from PyQt6.QtWidgets import QApplication, QWidget
from PyQt6.QtGui import QPainter, QColor
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt6.QtCore import QTimer, Qt
class NavigableSceneWidget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.angle_x = 0
self.angle_y = 0
self.scale = 1.0
self.translate_x = 0
self.translate_y = 0
self.translate_z = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.update)
self.timer.start(16)
def initializeGL(self):
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)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(self.translate_x, self.translate_y, self.translate_z)
glScalef(self.scale, self.scale, self.scale)
glRotatef(self.angle_x, 1, 0, 0)
glRotatef(self.angle_y, 0, 1, 0)
glBegin(GL_QUADS)
# 前面
glColor3f(1.0, 0.0, 0.0) # 红色
glVertex3f(-0.5, -0.5, 0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
# 后面
glColor3f(0.0, 1.0, 0.0) # 绿色
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(0.5, 0.5, -0.5)
glVertex3f(0.5, -0.5, -0.5)
# 上面
glColor3f(0.0, 0.0, 1.0) # 蓝色
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, -0.5)
# 下面
glColor3f(1.0, 1.0, 0.0) # 黄色
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(-0.5, -0.5, 0.5)
# 左面
glColor3f(1.0, 0.0, 1.0) # 品红色
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5, -0.5, 0.5)
# 右面
glColor3f(0.0, 1.0, 1.0) # 青色
glVertex3f(0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, -0.5)
glEnd()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(w) / float(h), 0.1, 100.0)
def mouseMoveEvent(self, event):
if event.buttons() & Qt.MouseButton.LeftButton:
dx = event.x() - self.width() / 2
dy = event.y() - self.height() / 2
self.angle_x += dy * 0.5
self.angle_y += dx * 0.5
elif event.buttons() & Qt.MouseButton.RightButton:
dx = event.x() - self.width() / 2
self.translate_x += dx * 0.01
def wheelEvent(self, event):
delta = event.angleDelta().y()
if delta > 0:
self.scale *= 1.1
else:
self.scale /= 1.1
if __name__ == '__main__':
app = QApplication(sys.argv)
scene_widget = NavigableSceneWidget()
scene_widget.show()
sys.exit(app.exec())
2.2.2 代码解析
此代码在立方体基础上添加了交互功能,允许用户通过鼠标操作控制视角:
- 初始化:添加旋转角度、缩放比例和平移量等状态变量,启动定时器定时更新画面。
- 鼠标事件处理 :
- 左键拖动:控制场景绕x轴和y轴旋转
- 右键拖动:控制场景沿x轴平移
- 鼠标滚轮:控制场景缩放
- 绘制:在绘制前应用旋转、缩放和平移变换。
2.2.3 技术要点
- 变换顺序:变换矩阵的应用顺序很重要,通常先缩放,再旋转,最后平移。
- 鼠标事件 :通过重写
mouseMoveEvent
和wheelEvent
捕获鼠标操作,实现交互控制。 - 定时器 :使用
QTimer
定时触发画面更新,确保平滑的动画效果。
3. 模型加载与动画
3.1 复杂3D模型加载与展示:虚拟博物馆展品呈现
3.1.1 代码实现
python
import sys
import open3d as o3d
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from PyQt6.QtCore import QTimer
from OpenGL.GL import *
from OpenGL.GLU import *
class ModelViewerWidget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.model = o3d.io.read_triangle_mesh("your_model.obj")
self.model.compute_vertex_normals()
self.timer = QTimer(self)
self.timer.timeout.connect(self.update)
self.timer.start(16)
self.angle = 0
def initializeGL(self):
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)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glRotatef(self.angle, 0, 1, 0)
vertices = self.model.vertices
triangles = self.model.triangles
colors = self.model.vertex_colors
glBegin(GL_TRIANGLES)
for triangle in triangles:
for i in range(3):
vertex_index = triangle[i]
vertex = vertices[vertex_index]
if colors:
color = colors[vertex_index]
glColor3f(color[0], color[1], color[2])
glVertex3f(vertex[0], vertex[1], vertex[2])
glEnd()
self.angle += 1
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(w) / float(h), 0.1, 100.0)
if __name__ == '__main__':
app = QApplication(sys.argv)
model_widget = ModelViewerWidget()
layout = QVBoxLayout()
layout.addWidget(model_widget)
main_widget = QWidget()
main_widget.setLayout(layout)
main_widget.show()
sys.exit(app.exec())
3.1.2 代码解析
此代码使用Open3D库加载并显示3D模型:
- 模型加载 :使用
o3d.io.read_triangle_mesh
加载OBJ格式模型,并计算顶点法线以增强光照效果。 - 绘制 :遍历模型的所有三角形面,为每个顶点设置坐标和颜色,使用
GL_TRIANGLES
图元绘制。 - 动画:通过定时器不断更新旋转角度,实现模型自动旋转。
3.1.3 技术要点
- 模型格式:支持多种格式,如OBJ、STL等,但需要确保模型文件路径正确。
- 顶点法线:计算顶点法线后,模型的光照效果会更自然,因为法线决定了光线反射方向。
- 性能考虑:对于大型模型,直接遍历所有三角形可能导致性能问题,实际应用中可能需要优化。
3.2 动画与交互效果实现:3D世界的动态交互
3.2.1 代码实现
python
import sys
import random
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt6.QtGui import QPainter, QColor
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt6.QtCore import QTimer, Qt
class AnimatedInteractiveWidget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.cube_x = 0
self.cube_y = 0
self.cube_z = 0
self.rotation_angle = 0
self.cube_speed_x = 0.05
self.cube_color = (1, 0, 0)
self.timer = QTimer(self)
self.timer.timeout.connect(self.update)
self.timer.start(16)
def initializeGL(self):
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)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(self.cube_x, self.cube_y, self.cube_z)
glRotatef(self.rotation_angle, 1, 1, 0)
# 绘制立方体
glBegin(GL_QUADS)
# 前面
glColor3f(self.cube_color[0], self.cube_color[1], self.cube_color[2])
glVertex3f(-0.5, -0.5, 0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
# 后面
glColor3f(self.cube_color[0], self.cube_color[1], self.cube_color[2])
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(0.5, 0.5, -0.5)
glVertex3f(0.5, -0.5, -0.5)
# 上面
glColor3f(self.cube_color[0], self.cube_color[1], self.cube_color[2])
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, -0.5)
# 下面
glColor3f(self.cube_color[0], self.cube_color[1], self.cube_color[2])
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(-0.5, -0.5, 0.5)
# 左面
glColor3f(self.cube_color[0], self.cube_color[1], self.cube_color[2])
glVertex3f(-0.5, -0.5, -0.5)
glVertex3f(-0.5, 0.5, -0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5, -0.5, 0.5)
# 右面
glColor3f(self.cube_color[0], self.cube_color[1], self.cube_color[2])
glVertex3f(0.5, -0.5, -0.5)
glVertex3f(0.5, -0.5, 0.5)
glVertex3f(0.5, 0.5, 0.5)
glVertex3f(0.5, 0.5, -0.5)
glEnd()
# 更新动画状态
self.cube_x += self.cube_speed_x
self.rotation_angle += 2
# 边界检测
if self.cube_x > 2 or self.cube_x < -2:
self.cube_speed_x *= -1
# 随机改变颜色
self.cube_color = (random.random(), random.random(), random.random())
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(w) / float(h), 0.1, 100.0)
def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
# 随机改变颜色
self.cube_color = (random.random(), random.random(), random.random())
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = AnimatedInteractiveWidget()
widget.show()
sys.exit(app.exec())
3.2.2 代码解析
此代码实现了一个具有动画和交互功能的立方体:
- 动画:立方体沿x轴移动并自转,到达边界时改变移动方向和颜色。
- 交互:点击左键随机改变立方体颜色。
- 定时器:使用定时器控制动画更新频率,确保流畅的动画效果。
3.2.3 技术要点
- 动画原理:通过在每一帧更新物体的位置和旋转角度,实现动画效果。
- 事件处理 :通过重写
mousePressEvent
捕获鼠标点击事件,实现交互功能。 - 边界检测:检测物体位置是否超出边界,实现反弹效果。
4. 医学可视化领域
4.1 3D人体器官模型展示
4.1.1 代码实现
python
import sys
from PyQt6.QtWidgets import QApplication, QOpenGLWidget
from PyQt6.QtCore import QTimer
from OpenGL.GL import *
from OpenGL.GLU import *
class OrganViewer(QOpenGLWidget):
def __init__(self):
super().__init__()
self.rotation = [0, 0]
self.timer = QTimer(self)
self.timer.timeout.connect(self.update)
self.timer.start(16)
def initializeGL(self):
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)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(5, 5, 5, 0, 0, 0, 0, 1, 0)
glRotatef(self.rotation[0], 1, 0, 0)
glRotatef(self.rotation[1], 0, 1, 0)
# 绘制简化肝脏模型(球体模拟)
glColor3f(0.6, 0.2, 0.2)
gluSphere(gluNewQuadric(), 1.5, 30, 30)
# 绘制简化肾脏模型(两个小球体)
glPushMatrix()
glTranslatef(-2, 0, 0)
glColor3f(0.2, 0.6, 0.2)
gluSphere(gluNewQuadric(), 0.8, 30, 30)
glPopMatrix()
glPushMatrix()
glTranslatef(2, 0, 0)
glColor3f(0.2, 0.6, 0.2)
gluSphere(gluNewQuadric(), 0.8, 30, 30)
glPopMatrix()
self.rotation[1] += 0.5
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60, w/h, 0.1, 50)
if __name__ == '__main__':
app = QApplication(sys.argv)
viewer = OrganViewer()
viewer.show()
sys.exit(app.exec())
4.1.2 代码解析
此代码使用简单几何形状模拟人体器官:
- 器官模型:使用球体模拟肝脏和肾脏,不同颜色区分不同器官。
- 动画:器官模型绕y轴缓慢旋转,便于从各个角度观察。
- 光照:启用光照效果,使器官模型具有立体感。
4.1.3 技术要点
- 几何建模:使用基本几何形状(如球体、圆柱体)模拟复杂器官,简化建模过程。
- 材质与颜色:通过不同颜色区分不同器官,提高可视化效果。
- 交互旋转:实现360度旋转,便于医生或研究人员全面观察器官结构。
4.2 医学影像切片3D重建预览
4.2.1 代码实现
python
# 简化版CT切片3D重建预览
import sys
import numpy as np
from PyQt6.QtWidgets import QApplication, QOpenGLWidget
from OpenGL.GL import *
class CTReconstructor(QOpenGLWidget):
def __init__(self):
super().__init__()
# 生成模拟CT切片数据
self.slice_data = np.random.rand(5, 30, 30) # 5层切片,每层30x30像素
def initializeGL(self):
glEnable(GL_DEPTH_TEST)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0)
# 绘制体素点
step = 0.5
glBegin(GL_POINTS)
for z in range(5):
for x in range(30):
for y in range(30):
value = self.slice_data[z, x, y]
glColor3f(value, value, value) # 灰度值表示
glVertex3f(x*step-7.5, y*step-7.5, z*step-1)
glEnd()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60, w/h, 0.1, 50)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = CTReconstructor()
win.show()
sys.exit(app.exec())
4.2.2 代码解析
此代码模拟CT切片的3D重建过程:
- 数据生成:使用随机数生成模拟CT切片数据,实际应用中应替换为真实的医学影像数据。
- 体素绘制:将每个像素值转换为3D空间中的一个点,点的亮度表示像素值大小。
- 视角控制:设置合适的视角,便于观察3D重建效果。
4.2.3 技术要点
- 体素表示:将2D切片数据转换为3D体素表示,是医学影像3D重建的基础。
- 透明度处理:实际应用中,通常需要根据像素值设置不同的透明度,以便更好地观察内部结构。
- 数据格式:真实医学影像数据通常采用DICOM格式,需要使用专门的库(如pydicom)进行读取和处理。
5. 建筑与室内设计展示
5.1 简单房间3D模型
5.1.1 代码实现
python
import sys
from PyQt6.QtWidgets import QApplication, QOpenGLWidget
from OpenGL.GL import *
from OpenGL.GLU import *
class RoomViewer(QOpenGLWidget):
def __init__(self):
super().__init__()
self.angle = 0
def initializeGL(self):
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(8, 5, 8, 0, 0, 0, 0, 1, 0)
glRotatef(self.angle, 0, 1, 0)
self.angle += 0.2
# 绘制房间墙壁
glColor3f(0.9, 0.9, 0.9) # 墙壁白色
# 地面
glBegin(GL_QUADS)
glVertex3f(-5, 0, -5)
glVertex3f(5, 0, -5)
glVertex3f(5, 0, 5)
glVertex3f(-5, 0, 5)
glEnd()
# 绘制家具(桌子)
glPushMatrix()
glTranslatef(-2, 0, -2)
glColor3f(0.6, 0.3, 0.1) # 木色
# 桌面
glPushMatrix()
glScalef(2, 0.1, 1.5)
glutSolidCube(1)
glPopMatrix()
# 桌腿
for pos in [(-0.8, 0, -0.6), (0.8, 0, -0.6), (-0.8, 0, 0.6), (0.8, 0, 0.6)]:
glPushMatrix()
glTranslatef(pos[0], -1, pos[2])
glScalef(0.1, 2, 0.1)
glutSolidCube(1)
glPopMatrix()
glPopMatrix()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60, w/h, 0.1, 50)
if __name__ == '__main__':
app = QApplication(sys.argv)
room = RoomViewer()
room.show()
sys.exit(app.exec())
5.1.2 代码解析
此代码创建了一个简单的房间3D模型:
- 房间结构:绘制了地面和简单的墙壁。
- 家具模型:添加了一张桌子,包括桌面和桌腿。
- 动画:房间缓慢旋转,便于全方位观察。
5.1.3 技术要点
- 层次结构 :使用
glPushMatrix()
和glPopMatrix()
管理变换矩阵,便于构建复杂场景。 - 材质模拟:通过颜色模拟不同材质,如白色墙壁和木色家具。
- 比例缩放 :使用
glScalef()
调整物体大小,确保各部分比例协调。
5.2 可切换材质的墙面展示
5.2.1 代码实现
python
import sys
from PyQt6.QtWidgets import QApplication, QOpenGLWidget, QComboBox, QVBoxLayout, QWidget
from PyQt6.QtCore import Qt
from OpenGL.GL import *
class WallMaterialViewer(QWidget):
def __init__(self):
super().__init__()
self.viewer = WallGLWidget()
self.combo = QComboBox()
self.combo.addItems(["白色涂料", "木质", "石材"])
self.combo.currentIndexChanged.connect(self.viewer.change_material)
layout = QVBoxLayout(self)
layout.addWidget(self.viewer)
layout.addWidget(self.combo)
self.show()
class WallGLWidget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.material = 0 # 0:涂料 1:木质 2:石材
def change_material(self, idx):
self.material = idx
self.update()
def initializeGL(self):
glEnable(GL_DEPTH_TEST)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(0, 3, 5, 0, 2, 0, 0, 1, 0)
# 根据材质设置颜色
if self.material == 0:
glColor3f(0.9, 0.9, 0.9)
elif self.material == 1:
glColor3f(0.7, 0.4, 0.2)
else:
glColor3f(0.5, 0.5, 0.5)
# 绘制墙面
glBegin(GL_QUADS)
glVertex3f(-3, 0, 0)
glVertex3f(3, 0, 0)
glVertex3f(3, 4, 0)
glVertex3f(-3, 4, 0)
glEnd()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60, w/h, 0.1, 50)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = WallMaterialViewer()
sys.exit(app.exec())
5.2.2 代码解析
此代码实现了墙面材质的动态切换功能:
- 用户界面:使用下拉框选择不同的墙面材质。
- 材质模拟:通过改变墙面颜色模拟不同材质效果。
- 交互更新:选择不同材质时,触发重绘事件更新显示。
5.2.3 技术要点
- 事件处理:使用信号槽机制连接下拉框的选择事件和OpenGL组件的更新函数。
- 材质系统:实际应用中可使用纹理映射替代简单的颜色模拟,实现更真实的材质效果。
- 用户交互:提供直观的界面元素,使用户能够方便地预览不同材质效果。
6. 教育培训中的虚拟实验
6.1 3D分子结构展示
6.1.1 代码实现
python
import sys
import math
from PyQt6.QtWidgets import QApplication, QOpenGLWidget
from OpenGL.GL import *
class MoleculeViewer(QOpenGLWidget):
def __init__(self):
super().__init__()
self.rotation = 0
def initializeGL(self):
glEnable(GL_DEPTH_TEST)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(5, 5, 5, 0, 0, 0, 0, 1, 0)
glRotatef(self.rotation, 0, 1, 0)
self.rotation += 0.5
# 绘制水分子结构(O原子+2个H原子)
# 氧原子
glColor3f(