一个多线程、支持OpenGL的应用程序。






4.92/5 (49投票s)
提供了一个基础,用于编写实际的OpenGL应用程序,而不是简单的“Hello World”程序。
序言
正如大多数学习OpenGL的人所发现的,它为开发人员直接访问计算机的底层图形硬件和/或GPU提供了一种绝佳的方式。然而,它不提供任何与主机操作系统环境协同工作的机制。
这包括系统IO、窗口化、计时等,仅举几例。填补这一空白的传统方法是使用另一个库来处理具体细节。这种方法的好处是抽象可以实现平台无关的GUI等操作。但是,与大多数抽象一样,底层的操作系统功能(随时可以选取和调整)被隐藏起来。
第二种方法是直接与平台特定功能接口,以实现所需的额外功能。这种方法不允许平台无关的代码,但它允许您精细控制应用程序的工作方式,并且没有额外的开销。作为一名长期从事Windows开发的开发人员,我选择了这条路,因为对我来说,速度很重要,并且能够从Windows中精确地获得我想要的东西也很重要。
因此,我提出了一个基于Windows的骨架应用程序,它承载了一个OpenGL渲染环境。与大多数其他基于OpenGL的骨架或向导不同,这个应用程序的功能更完善,足以创建真实世界的应用程序,而不是“Hello World”场景,并且实际上使用多线程在较新的系统上实现性能提升。
目标
这个应用程序的目标是提供启动和运行OpenGL渲染环境所需的繁琐工作,除了Windows默认提供的库之外,不使用任何外部库。这还允许我们使用一套经过良好测试和调试的通用集。
设计遵循KISS原则。它没有包含所有与OpenGL命令不直接相关的世界功能,而是包含了您所制作的几乎每个应用程序中都会存在的功能。然而,它确实包含足够的结构,以便您可以根据需要插入额外功能。
特点
- 基于时间的动画
游戏动画中一个由来已久的问题是,当在比游戏设计时更快的CPU/GPU上运行时,游戏会因为运行过快而变得无法玩。反之亦然。如果游戏是在快速系统上设计的,但在较慢的系统上运行,动画可能会太慢。
因此,骨架应用程序采用了一种称为基于时间的动画技术,该技术在动画时使用计算机每秒渲染一帧所需的CPU周期量作为乘法因子。使用这种方法可以实现平滑的动画,而与帧率无关。
- 多线程
骨架应用程序利用了多线程范式。它使用一个线程来处理Windows特定的处理,并使用一个单独的线程来处理OpenGL的特定处理。这有两个明显的优点。第一,这将在使用超线程和/或双核技术的现代CPU上实现性能提升。第二,这也确保了OpenGL渲染管道的更平滑操作,因为它不会被Windows消息处理(为了用户与应用程序交互而必需)所瓶颈。
- 线程间通信
在应用程序中,两个线程可以通过消息系统进行通信。主线程可以使用
PostThreadMessage()
API与渲染线程通信,渲染线程可以使用SendMessage()
API与主线程通信。这为两个线程共享信息提供了一种可定制、可扩展的方式。 - 序列化
实际上,任何基于Windows的应用程序都倾向于使用某种方式来保存和恢复设置。一种非常流行的方法是利用Windows注册表。因此,应用程序支持在Users Hive下读写注册表,但可以很容易地进行修改,使其也能写入System Hive等。
默认情况下,骨架应用程序将检查BPP数据、主窗口定位数据以及全屏模式下使用的垂直刷新率。
- 命令行解析
如果一个应用程序不使用命令行,那它会是什么样子呢?这个骨架应用程序允许您轻松添加对任意数量命令行选项的支持。默认情况下,它会检查一个
/fullscreen
选项,允许用户指定是希望以全屏模式还是窗口模式运行。 - 调试宏和信息
仅在调试模式下,骨架应用程序会做两件额外的事情
首先,它会在主窗口的标题栏上为您提供状态信息,显示系统上安装的OpenGL版本和帧率 (FPS)。这些信息对于确定您的安装实现能做什么以及性能调整非常有用。
其次,它启用了两个名为ENTER_GL和LEAVE_GL的调试宏,旨在用于包围OpenGL调用代码块。OpenGL的错误处理机制并不直接,这些宏将有助于缓解这个问题。应用程序本身演示了它们的用法。
- 广泛的配置选项
为了适应许多不同的场景,骨架应用程序在
WinMain.h
中使用了预处理器指令来启用、禁用或配置要使用的功能。下面是对一些可能引起混淆的指令的描述CONFIG_ALLOW_FULLSCREEN 如果您希望允许应用程序进入全屏模式,请将其设置为 true
;否则设置为false
。注意:如果设置为false
,它将覆盖所有其他与全屏相关的设置(注册表、命令行等)。CONFIG_ALLOW_RESIZE 如果您希望允许主应用程序窗口调整大小,请将其设置为 true
;否则设置为false
。注意:如果设置为false
,应用程序将不考虑任何有关窗口大小的信息(只考虑位置)。CONFIG_ALLOW_MENU 如果您希望在主应用程序窗口上允许标准Windows菜单,请将其设置为 true
;否则设置为false
。注意:如果为true
,应用程序假定菜单的资源ID是IDR_MAINFRAME。此外,默认情况下,ESC键将显示和隐藏菜单。这样做将使用户能够腾出更多屏幕空间。CONFIG_ALLOW_VSYNC 如果您希望允许应用程序调整显卡帧率的垂直刷新率同步 (VSync),请将其设置为 true
。注意:如果为true
,它会根据系统和配置是否可能来尝试打开或关闭VSync。如果不可能或设置为false
,无论设置如何,它都不会执行任何操作。如果允许,VSync可以通过注册表中的VSync
键来打开或关闭。CONFIG_DEF_BPP 如果应用程序处于全屏模式,则使用的默认每像素位数 (BPP)。注意:这可以通过在注册表中设置 BPP
键来覆盖。CONFIG_DEF_FULLSCREEN 如果允许全屏模式,则如果您希望应用程序默认全屏模式,请将其设置为 true
,如果您希望默认窗口模式,请设置为false
。注意:目前,/fullscreen
开关可以覆盖此设置,因为它只是一个默认值。CONFIG_DEF_HEIGHT
CONFIG_DEF_WIDTH主应用程序窗口的默认宽度和高度。注意:如果窗口不允许调整大小,这将始终是主窗口的大小。 CONFIG_MAX_REFRESH
CONFIG_MIN_REFRESH默认情况下,应用程序将在注册表中查找用于全屏模式的垂直刷新率,键为 Refresh
。这两个设置将确定允许的最大和最小刷新率,作为安全预防措施。CONFIG_MIN_HEIGHT
CONFIG_MIN_WIDTH允许您指定主应用程序窗口的最小宽度和高度。如果设置,窗口不能调整到低于这些点。注意:将这些设置为 0
实际上意味着没有最小值。CONFIG_SINGLE_INSTANCE 如果您希望应用程序限制为单个实例(使用互斥体),请设置为 true
;否则,设置为false
。
关注点
- C语言优于C++的使用
骨架应用程序是用C语言而不是C++编写的。你们中的许多人可能更喜欢使用C++,这无可厚非。将应用程序的功能封装到几个类中应该足够容易。我个人对C++没有偏见,但我选择C语言更多是出于实用考虑,而非哲学理念。
由于使用C语言,骨架应用程序定义并使用了
bool
和tribool
数据类型,类似于C99布尔定义和C++ Boost库的三态布尔类型。 - 源代码关键区域
- Main\Application.h
这是主要的应用程序包含文件,其中包含本文概述的配置选项。
- 渲染委托
虽然大部分代码都相对一目了然,但值得注意的是,传递给渲染线程的
RENDERARGS
结构体中的pRenderFrame
委托函数将是OpenGL中要渲染的任何内容的起点。它将每帧调用一次,所有不包括预加载等的渲染操作都应从此函数派生。
- Main\Application.h
示例应用程序
可下载的应用程序项目还演示了骨架的简单用法,以动画任天堂著名塞尔达系列中的 Triforce。它们是为清晰起见编写的骨架示例。此外,它们还利用了本文中提到的基于时间的动画。
需要注意的是,如果您使用的是 Visual Studio 2017,还需要安装 Windows 8.1 SDK,因为它默认不包含。这是因为 Microsoft 正在使 Visual Studio 的分发更加模块化。
鸣谢和历史
应用程序图标 - | 由 iconshock.com 慷慨提供,作为其SIGMA Graphics系列的一部分。 | |
|