3D图形应用程序的可自定义架构






4.88/5 (28投票s)
通过一个基本的OpenGL应用程序,解释了一个统一的3D图形软件架构。
1. 引言
本文包含用于创建 3D 图形应用程序基础架构的信息和构建工件。其主要目标是作为构建各种 CAD 应用程序的起点,重用所解释的架构作为图形软件的设计模式。
2. 背景和涵盖的主题
本文的预期读者是具有 C++ 编程和软件方法学强大背景的软件分析师和软件工程师。因此,为了很好地理解本文,您最好精通以下主题:
- UML 2.0。
- 软件方法学。
- 设计模式。
- ANSI/ISO C++ 面向对象编程。
- GUI 编程和设计。
- 3D 图形基础数学。
本文旨在传达这样一种概念:一组类可以独立于所使用的语言或框架,在面向对象范式中促进 3D 图形软件的构建。
3. ISSIGraph 项目
ISSIGraph 项目被构想为曲面建模器作业的基础原型。它是由国家远程教育大学 (UNED) 的软件工程和计算机系统系开发的。最新的更改和更新体现在您在此处看到的成果中。为了设计和实现该工具,我遵循了一种类似于 RUP (Rational Unified Process) 的小型方法。在接下来的章节中,您将能够看到用于编写ISSIGraph 的主要软件工程生命周期。
3.1 要求
在我构思ISSIGraph 应用程序时,我试图满足以下功能和非功能性要求。
3.1.1 功能要求
ISSIGraph 应用程序应允许轻松地以线框方式绘制 Bezier 和 NURBS 曲面,以及任何其他曲面,如球体、圆锥体、圆柱体、茶壶、环面等。此外,还必须能够渲染 3D 文本。所有这些对象都必须能够以简单直接的方式在场景中移动、旋转和缩放。
该应用程序应支持 BMP、JPEG 和 PNG 文件格式导出,并可以更改背景颜色,以及导出屏幕内模型的 XML。
与其他自定义图形应用程序一样,用户应自由执行复制、粘贴和剪切操作,以及撤销/重做操作。最后,应用程序应允许在初始 1024 x 768 窗口外部的虚拟空间中移动、旋转和缩放 3D 对象,方法是使用控制器面板。
3.1.2 非功能性要求
以下列出了一些最重要的性能和环境要求:
- 以最低的 CPU 成本实现高性能。
- 复杂度为 O(n) 的算法。
- OpenGL 作为 3D 库。
- 跨平台:Windows、Linux 和 Mac OS X。
- 使用 wxWidgets 2.9.3 框架。
- 低内存开销。
- 吸引人的设计。
- 易于安装和使用。
- 安全系统。
- 可读代码。
- 以开源形式发布。
3.1.3 用例
用例图有助于捕获实现ISSIGraph 应用程序所需的请求。图的左侧是与系统交互的主要参与者;右侧是主要用例:
图 1。 用例图
3.2 架构
ISSIGraph 的基本架构基于三层应用程序。如下所示,自下而上的层执行用户界面管理,中间层执行业务逻辑,底层处理图形和硬件库。最后,所有这些层都建立在平台实现之上。

图 2。 架构布局
3.3 高层设计
3.3.1 用户界面
如[1]所述,用户界面的目标是:
A) 将控制权交给用户
- 定义交互模式,以便用户不必执行不必要的操作。
- 考虑灵活的交互。
- 用户交互必须是可中断和可撤销的。
- 向用户隐藏技术复杂性。
- 直接与屏幕对象交互。
B) 减轻用户内存负担
- 减少短期记忆需求。
- 使用默认值。
- 使用快捷方式。
- 视觉格式必须是世界的隐喻。
- 使用嵌套菜单。
C) 构建一致的界面
- 允许用户在合适的上下文中执行任务。例如,对象选择器。
- 在应用程序系列中保持一致性。
- 使用助记规则。
图 3。 用户界面
3.3.2 数据管理
为了实现持久性,我没有使用序列化,因为这不适合信息交换。为了实现具有互操作性和信息可移植性的持久性,我选择使用 XML 文件格式,编码为 UTF-8。 XML 是一个结构良好的规范,允许您组织和交换数据以供以后使用。您可以在此处查看用于在ISSIGraph 中存储 3D 模型的 XML 示例。
3.4 详细设计
3.4.1 类图
3.4.1.1 演示子系统
该子系统负责通过wxWidgets 用户界面框架管理用户交互。IssiFrame
类包含对 IssiGLCanvas
的引用,这是一个适合渲染 OpenGL 基元的上下文。此类启动并处理OnPaint 事件。此子系统通过向业务域对象发送消息与 World 子系统进行交互。
图 4。 演示子系统
3.4.1.2 基本层次子系统
该子系统是应用程序中其余对象继承的核心基类。Box
抽象类允许您管理和实现后续继承类的行为;但它在 QuadricBox
和 VertexBox
核心基类中被覆盖。
图 5。 基类
3.4.1.3 曲面子系统
这是从 Box
类继承的第一个子系统。VertexBox
核心类允许您实现 NURBS、Bezier 和控制点 3D 数学特殊要求。
图 6。 曲面子系统
3.4.1.4 二次曲面子系统
与曲面子系统一样,该子系统允许您实现基本 3D 曲面,如立方体、茶壶、球体、圆锥体等。最终继承的类,如 Cylinder
、Cone
、Torus
等,实现了在 QuadricBox
和 Quadric
等顶层核心类中定义的虚拟行为。请注意,OneDimension
和 TwoDimension
类实现了更改体积尺寸(如高度和宽度)的设施。
图 7。 二次曲面子系统
3.4.1.5 世界子系统
最后,World
类是接收来自演示子系统wxWidgets 框架生成的事件的所有消息的接收对象。该子系统实现了所有与业务逻辑相关的行为,即整个ISSIGraph 应用程序的功能。
Axis
类实现了可移动的坐标系统,它继承自 VertexBox
抽象类。Memory
类实现了用于复制/粘贴/剪切以及撤销/重做过程的内存操作的小型设计模式。
图 8。 世界子系统
3.4.1.6 工具子系统
这组简单的类是一个帮助系统包,包含所需的数学、库特定和转换例程。它们被分组为静态成员函数,对应用程序的正确性和组织性很有用。
图 9。 工具子系统
图 10。 序列图
- 用户想移动整个
NURBS
。他将其通知给IssiGLCanvas
对象。 IssiGLCanvas
对象向World
对象报告。World
对象(根据业务逻辑)报告要移动的 NURBS。NURBS
对象向上调用其Surface
基类。Surface
对象迭代存储在列表中的所有CtrlPoint
对象以移动它们。- 现在,用户想更改环面的尺寸,所以他将其通知给
IssiGLCanvas
对象。 - 同样,
IssiGLCanvas
对象向World
对象报告。 World
对象对Torus
对象执行操作。- 因为环面对象有两个维度(内半径和外半径),所以它被通知给
TwoDimension
对象。 - 现在用户想移动
Axis
对象。 - 同样,
IssiGLCanvas
向World
对象报告。 - World 对象(根据业务逻辑)报告
Axis
。 - 突然,发生了一个 ONPAINT 事件。
- 因此,
ISSIGLCanvas
通知 World 对象的渲染方法。 World
对象调用其NURBS
对象来处理其控制点。- 根据这一点,
NURBS
处理其所有控制点。 - 现在,World 的渲染例程必须绘制其
NURBS
。 - 因此,
NURBS
迭代以绘制其所有控制点。 - 同样,World 的渲染例程必须绘制其
Torus
对象, - 以及绘制选择矩形(
DrawBox
), NURBS
的选择矩形(DrawSelection
)处理程序,- 以及
Torus
的选择处理程序。 - 最后,World 的渲染例程绘制
Axis
(坐标系统)。
3.5 实现
3.5.1 编译器
整个应用程序是用 C++ 在Windows XP 32 位版本的Visual C++ 2010 Express Edition 编译器上开发的。之后,该应用程序被移植到Linux (使用 GNU-GCC 4.9),最后,Leopard Mac OS X 版本使用 X-Code GCC 4.0 和 GNU Make 进行移植。
3.5.2 库
为了实现合适的 3D 图形输出和最先进的 3D 应用程序,我使用了 OpenGL 库进行基元绘制,并使用 GLUT 进行二次曲面和文本输出。如[2]所述,我选择使用 GLEW 库进行 NURBS 和 Bezier 绘制,而不是实现一个算法来细分它们。然而,在 Linux 和 Mac 版本中,我不得不使用freeglut 进行 GLUT 基元。
3.5.3 框架
我用于所有应用程序的通用框架是wxWidgets 2.9.3 版本,因为它是一个免费稳定的软件,用于跨平台用户界面实现。
3.5.4 代码分发
分发的代码具有以下结构
源文件 | 含义 |
main.h | 用户界面主头文件 |
main.cpp | 用户界面主实现文件 |
box.h | 基本子系统头文件 |
box.cpp | 基本子系统实现文件 |
surface.h | NURBS、Bezier 和控制点 头文件 |
surface.cpp | NURBS、Bezier 和控制点实现类 |
quadric.h | 二次曲面、体积和文本头文件 |
quadric.cpp | 二次曲面、体积和文本实现类 |
textout.h | GLUT 文本例程类头文件 |
textout.cpp | GLUT 文本例程类实现文件 |
world.h | 世界子系统头文件类 |
world.cpp | 世界子系统实现类 |
tool.h | 工具子系统头文件类 |
tool.cpp | 工具子系统实现类 |
表 1。 源代码文件目录结构
3.6 测试
根据[1],应用于ISSIGraph 测试的动态技术可以确保应用程序的质量。
3.6.1 白盒测试
这项技术试图根据程序的内部结构来检查程序逻辑。也就是说,它允许查看应用程序的内部(这将是一个符号框)。
由于在 100% 的情况下进行穷尽和完整的测试是不切实际的,我试图进行代码覆盖,包括所有基本语句、决策和条件路径,以及纸上审查作为软件度量。
3.6.2 黑盒测试
通过这项技术,我试图根据执行的函数规范来检查应用程序的行为。之所以这样称呼,是因为它不关心应用程序的内部,而是执行响应。
为了执行黑盒测试,我使用了边界值分析,例如使用少量控制点和对象与大量控制点和对象进行比较。
为了展示良好的应用程序性能,我设计了两个黑盒测试用例(A 和 B)作为有用的压力测试,使用了以下系统设备:
- Mac Book Pro
- Intel CPU 搭载 Core i5 (四核) M529 2.40 GHz @ 1.17 GHz
- 2.17 GB RAM
- Windows XP 32 位操作系统
- NVidia GeForce GT 330M
案例 A
- 3 个圆锥体
- 2 个环面
- 1 个茶壶
- 1 个二十面体
- 1 个十二面体
- 1 个菱形十二面体
- 1 个文本
- 1 个 NURBS
- 1 个 Bezier
- 1 个坐标系统
图 11。 案例 A
旋转整个场景时的性能和开销是
图 12。 A 中的系统性能
案例 B
- 2 个茶壶
- 2 个 NURBS

图 13。 B 案例
在此案例中,对象被放大 4 倍,因此性能是

图 14。 B 中的系统性能
4. 版本和功能
ISSIGraph 应用程序已通过 GPLv3.0 许可在 Web 网站 SourceForge.NET 上发布,网址为:http://issigraph.sourceforge.net 。在同一 URL 上可以找到 Win32、Linux 和 Mac 的可执行文件和源代码的下载部分。一个关于如何使用主要功能的完整教程托管在 http://issigraph.sourceforge.net/docs.html,您可以在那里找到所有有关使用程序和构建曲面的说明。
5. 贡献
如果您有兴趣为ISSIGraph 做出贡献并创建一个真实的 3D 应用程序,只需在 Codeproject 论坛或SourceForge.NET 论坛上给我留言,我会审核您的提案。 以下列出了一系列未来目标:
- 添加新曲面(立方体、线、三角形、圆、插值...)
- 添加材质
- 添加纹理
- 添加灯光
- 添加阴影
- 改进定位系统
- 导入/导出 3D 模型
- 其他想法
因此,如果您想实现上述任何想法或有任何其他好主意,欢迎您!
6. 1.41 版本中的新功能
- 能源优化,小于 1%(仅在屏幕需要重绘时渲染)
- 改进的内部复制/粘贴/剪切
- 改进为单步循环撤销/重做
- 修复了 Windows 7 和 8 版本中的闪烁错误
- 修复了一些恼人的错误
- 编译到警告级别 4(Visual C++ 和 g++ 的最高级别)
7. 延伸阅读和参考资料
[1] Robert S. Pressman。 "软件工程:实践方法(第五版)"。 McGraw-Hill。
[2] Donald Hearn 和 Pauline Baker。 "Computer Graphics with OpenGL (第三版)"。Pearson - Prentice Hall。
[3] Juan M. Cordero Valle 和 José Cortés Parejo。"几何建模"。 Ra-ma。
[4] Bjarne Stroustrup。 "C++ 编程语言(第三版)" 。Addison-Wesley。
[5] Julian Smart 和 Kevin Hock。 "使用 wxWidgets 进行跨平台 GUI 编程"。Prentice Hall。
[6] Shaw Garlan。 "软件架构导论"。World Scientific Publishing Company。
[7] Raphael Malveau 和 Thomas J. Mowbray 博士。 "软件架构训练营"。Prentice Hall。