《PyQt6-3D应用开发技术文档》

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 技术要点
  1. 深度测试 :通过glEnable(GL_DEPTH_TEST)启用深度测试,确保3D物体正确显示前后关系。
  2. 光照模型 :使用glEnable(GL_LIGHT0)glEnable(GL_LIGHTING)启用光照效果,使立方体有明暗变化。
  3. 坐标系统: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 技术要点
  1. 变换顺序:变换矩阵的应用顺序很重要,通常先缩放,再旋转,最后平移。
  2. 鼠标事件 :通过重写mouseMoveEventwheelEvent捕获鼠标操作,实现交互控制。
  3. 定时器 :使用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 技术要点
  1. 模型格式:支持多种格式,如OBJ、STL等,但需要确保模型文件路径正确。
  2. 顶点法线:计算顶点法线后,模型的光照效果会更自然,因为法线决定了光线反射方向。
  3. 性能考虑:对于大型模型,直接遍历所有三角形可能导致性能问题,实际应用中可能需要优化。

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 技术要点
  1. 动画原理:通过在每一帧更新物体的位置和旋转角度,实现动画效果。
  2. 事件处理 :通过重写mousePressEvent捕获鼠标点击事件,实现交互功能。
  3. 边界检测:检测物体位置是否超出边界,实现反弹效果。

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 技术要点
  1. 几何建模:使用基本几何形状(如球体、圆柱体)模拟复杂器官,简化建模过程。
  2. 材质与颜色:通过不同颜色区分不同器官,提高可视化效果。
  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 技术要点
  1. 体素表示:将2D切片数据转换为3D体素表示,是医学影像3D重建的基础。
  2. 透明度处理:实际应用中,通常需要根据像素值设置不同的透明度,以便更好地观察内部结构。
  3. 数据格式:真实医学影像数据通常采用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 技术要点
  1. 层次结构 :使用glPushMatrix()glPopMatrix()管理变换矩阵,便于构建复杂场景。
  2. 材质模拟:通过颜色模拟不同材质,如白色墙壁和木色家具。
  3. 比例缩放 :使用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 技术要点
  1. 事件处理:使用信号槽机制连接下拉框的选择事件和OpenGL组件的更新函数。
  2. 材质系统:实际应用中可使用纹理映射替代简单的颜色模拟,实现更真实的材质效果。
  3. 用户交互:提供直观的界面元素,使用户能够方便地预览不同材质效果。

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(
相关推荐
sword devil90013 小时前
PYQT实战:无刷电机模拟(只是模拟,没有写接口接收外部数据)
pyqt
鹧鸪云光伏15 小时前
光伏无人机3D建模:毫秒级精度设计
3d·无人机
杀生丸学AI17 小时前
【三维生成】FlashDreamer:基于扩散模型的单目图像到3D场景
人工智能·3d·大模型·aigc·蒸馏与迁移学习·扩散模型与生成模型
gis分享者1 天前
学习threejs,使用自定义GLSL 着色器,生成漂流的3D能量球
3d·threejs·着色器·glsl·shadermaterial·能量球
m0_743106461 天前
【论文笔记】BlockGaussian:巧妙解决大规模场景重建中的伪影问题
论文阅读·计算机视觉·3d·aigc·几何学
向宇it2 天前
【unity小技巧】在 Unity 中将 2D 精灵添加到 3D 游戏中,并实现阴影投射效果,实现类《八分旅人》《饥荒》等等的2.5D游戏效果
游戏·3d·unity·编辑器·游戏引擎·材质
荔枝味啊~2 天前
相机位姿估计
人工智能·计算机视觉·3d
在下胡三汉3 天前
什么是 3D 文件?
3d
点云登山者4 天前
登山第二十六梯:单目3D检测一切——一只眼看世界
3d·3d检测·检测一切·单目3d检测