基于OpenSceneGraph引擎的机车车辆模拟器中的三维可视化



不到一年之前,我们出版了一份出版物 ,讨论了我们大学开发的ES1 Lastochka电动火车的培训和实验室综合体(ULK)。 然后,我保证这将不是该主题的最新出版物,尤其是,我扬言要谈论为此类模拟器创建三维可视化的问题,并概述解决这些问题的主要方法。

去年,我们对下一个版本感到满意,Sapsan高速电动火车EVS2的ULK于去年8月发布。 电动火车本身的教育和实验室综合体本身值得一个单独的故事,但在本出版物的背景下,我们将讨论疼痛-创建足够的三维可视化子系统的问题,我们的团队从不同方面解决了大约两年的问题。 Peregrine Falcon模拟器的发布非常重要(除其他事项外),因为它确定了我们在这一领域的发展动力。

1.简要介绍ULK EVS2“ Sapsan”


我想再次强调一下(我以令人羡慕的频率这样做),我们大学开发的机车车辆的教育和实验室综合设施并不是为了准备机车旅而设计的。 正如上一篇文章的评论者所正确指出的那样 ,我们的ULK不是模拟器,而是模拟器,其主要重点是火车运动物理学的有效实施以及机车子系统的运行模拟,以确保其运动和停止。 Sapsan模拟器也不例外,可以解决以下任务:

  • 考虑到纵向力和轨道轮廓,实现了火车机械部分的动态模型
  • 建立了电动火车关键子系统运行的详细计算机模型:动力电路,牵引电驱动,气动和电动气动制动器
  • 再现了不同级别的电动火车控制系统操作的基本算法。

此外,培训和实验室综合设施还包括电动火车车厢的全尺寸模型,以及主要控制装置和显示信息的装置。 与“燕子”模拟器不同,该机舱不是我们自己制造的,而是在2015年从该国生产培训模拟器的一家办事处购买的。 因此,模拟器的开发过程集中在创建软件上。

客舱照片
机舱内部的一般视图


透过挡风玻璃查看


显示集成机车安全装置(CLUB-U)。 红色的“ 290”是从CLUB-U电子卡获得的当前速度限制。 到目前为止,萨普桑(Sapsan)在十月铁路上达到的车速极限在这里突兀。 将来,电子卡将像在生活中一样实现。


主显示“人机界面”


显示电动火车制动系统的状态


速度调节器和牵引力控制器


电动火车制动控制控制器


用于控制集电器和保护装置(BV / GV)的拨动开关-速度设定器附近的黑色拨动开关


培训管理界面-路线选择屏幕


音频效果音量控制屏幕


里程计数器。 一个有趣的故事与他的外表有关。 当我们交出第一台2TE116柴油机车模拟器时,客户代表开玩笑地问我们何时完成签字:“好吧,让我们像生活中那样做-当一台新机车投入运行时,它必须经过5000公里的运行。 那将过去……”。 该法案当然早就签署了,但为了评估形势的幽默,我们已经在Swallows模拟器上做了一个类似的计数器。 输入服务密码可将计数器重置为“ 0”。


右侧附件面板带有制动压力表和紧急制动阀。 并非Sapsan固有的所有元件都安装在此处-我们从供应商处收到了这样的遥控器


因此,某些对我们至关重要的控件已通过软件实现,特别是通过触摸屏控制的旁路开关面板


这种模拟器模拟器的软件开发是一个非常广泛的问题,我将尽我所能(尽我所能)满足读者对这些问题的兴趣(如果有的话),但是现在让我们回到本文的主要主题-火车运动过程的三维可视化。

2.过去的背景和技术


在上一篇文章的评论中,有人问了一个问题 ,坦率地说,这使我很开心。 是的,确实,的确,在当今仍在使用的许多模拟器中,仍然使用这种方法:在铁路的真实部分上拍摄视频,然后在模拟器上以与移动速度成比例的速度滚动视频。 这样做是因为在创建此类模拟器的那个遥远的时代,三维图形的质量迫在眉睫,而且这也适用于商用Unix上的苛刻图形站,而PC毫无疑问。 因此,即使是计算机游戏的制造商,例如这一制造商,也毫不犹豫地使用这种方法。

今天这没有意义,因为:

  1. 在低火车速度下帧速率不足,无法提供所需的图像刷新平滑度。 仅当从驾驶室拍摄视频时,我们才会珍惜25 fps。 而且这种致命的缺陷无法以任何方式克服-既不能通过高速相机拍摄(以每秒120帧的速度拍摄的视频重多少?那是相同的...),也不能通过编程的中间帧生成。 后者是由我们使用OpenCV技术进行的,但未获得正常结果。 各个方面对此问题进行了反复研究,结果得出结论,创建这种系统的资源成本比基于3D图形的类似系统的开发成本高得多。
  2. 难以顺利向后滚动视频。 甚至考虑到它们将被克服,那么在平台上运行的狗将在哪里运行,我们认为我们应该逆转吗?
  3. 缺乏所有的“互动性”。 与交通信号灯的变化,道岔的移动,迎面而来的火车的移动怎么办?

因此,所有现代模拟器和模拟器都是使用交互式3D图形创建的,因为从软件或硬件的角度来看,今天都没有障碍。

如果从硬件的角度来看一切都很清楚-安装的显示器而不是挡风玻璃通过普通的视频卡(甚至不是高端显卡)连接到PC,那么从软件的角度来看,选择执行任务的技术就成为问题。

3.图形引擎与游戏引擎还是为什么选择OpenSceneGraph


我可能会误会,但是我希望事先发表评论,这将提出一个完全合乎逻辑的问题,为什么在分析现有技术时,我们的选择没有停留在Unity或Unreal Engine 4等障碍物上? 我将回答这个问题,此外,我将给出答案。

简要地说-Unity和Unreal Engine都不满足要解决的任务的要求。 首先,更详细的答案提供了相关需求的列表。 我们在三维可视化子系统上编译的传统知识,包括(按重要性从高到低的顺序)以下规定:

  1. 可视化子系统的软件开发过程与为其创建资源的过程无关。 在这种情况下,资源包括三维模型,纹理以及所谓的路线 。 路线被理解为配置对象和资源的组合,允许视频子系统显示铁路的所需部分并提供列车沿其运动的模拟。 这还包括无需重新构建视频子系统的软件部分即可更改路线可能性
  2. 创建无限长度的路由。 我会保留一点,由于有限的硬件资源,原则上无法达到无限长。 应当理解这一要求,路线的长度应至少在一个“路肩”之内,即转弯点之间的路段,并且根据各种因素,这是足够大的距离,估计超过一百公里。 该要求要求提供具有合理的内存消耗,足够的平滑度的动态加载/卸载程序资源。 希望引擎“开箱即用”包含此类功能
  3. 与使用过的技术堆栈的便捷集成。 传统上,出于客观原因,我们的团队再次使用具有Qt框架,QtCreator IDE和Git的C ++语言作为版本控制系统来开发用于ULK PS的软件。 作为系统平台ULK PS,使用了基于Linux内核的OS。

Unity和UE有什么问题? 其他引擎能够导入完全不同格式的资源的事实是什么。 但是,在组装项目时,它们会不可逆地转换为内部二进制格式,这使得在不重新组装项目的情况下无法添加和更改资源。 Unity中可用的预制件和资产捆绑包之类的技术无法解决问题,因为引擎编辑器不是创建铁路位置的最佳场所,这需要扩展编辑器,这导致需要在引擎内部编写“引擎”。 此外,如果不使用Unity编辑器,则无法创建预制件和捆绑包,而且正如实践所示,这不是很方便,特别是对于纯建模人员和关卡设计师而言。 对于UE,两年来,我在有关此资源和其他资源的问题上问了很多问题,这些问题涉及如何将项目的构建过程与添加/更改其使用的资源的过程区分开来,在文档或“资深的游戏开发商。 如果我合理地迷失了自己想念的东西,我会很高兴(没有讽刺意味)。

至于第二个要求,Unity和UE似乎都可以创建动态加载的位置,但是问题仍然没有得到解决,如何在不重新创建项目的情况下独立于编辑器创建这些位置? 仅有的出路-在引擎内部编写“引擎”,它将加载“原始”(以3D编辑器先前指定的任何导出格式)几何和纹理,对其施加所有必要的效果,并根据第三方描述的数据将其放置在空间中与引擎格式无关,仍然需要开发和教导以解释引擎。

结合以上所述,出现了一个问题-如果要解决此问题,有必要在游戏引擎上编写功能强大的软件层,而在所考虑的问题中根本不需要其大部分功能,那么我们为什么需要游戏引擎?

也许图形引擎就足够了? 我向上一个团队询问了这个问题,该团队依靠Unity来解决正在讨论的问题(并在稍后合并)。 作为回应,他收到了一个反问:“你有什么建议?”,根据上述内容,他回答了对方的讽刺微笑。

如果您毫不客气,那么提出的任务就是典型的可视化任务-它只需要一个用于处理图形的框架,因为物理层和基于物理层的音频子系统都是在服务器端实现的。 我和我的团队逐渐了解了这一事实,通过先前的开发人员的惯性,首先通过UE向Unity迈进,并尝试从一个开放的铁路模拟器(实际上是OpenBVE,但后来变成了临时的拐杖)中固定图形子系统。

OpenSceneGraph是迄今为止专注于C ++开发的最先进的(开放和免费)图形引擎。 在国外,它广泛用于技术三维可视化。 该引擎没有被任何一种模拟器所幸免,其中最著名的是FlightGear 。 曾经有一个基于此引擎的铁路模拟器Indra ,但是,上面仅留下了链接的晦涩屏幕截图,而我的命运还不为人所知。

在当前任务的背景下,OSG图形引擎具有以下积极特性:

  • 跨平台,使其可以在GNU / Linux生态系统中应用
  • 开发语言是C ++ / STL,它可以轻松自然地将其集成到已建立的开发技术流程中;
  • “开箱即用”支持最广泛的资源格式-由于开发了插件系统,因此3D几何和纹理。 一个简单直观的界面,用于编写您自己的插件以将资源管理器设置为非标准格式(我们将在下面使用它);
  • 一种基于智能指针专有模型的内存管理系统(由于开发初期C ++标准中没有智能指针引擎,因此历史上一直使用智能指针的专有格式);
  • 灵活的模块化架构;
  • 场景对象管理器,它动态加载对象,仅提供位于剪切金字塔内的那些对象的加载和渲染(由于osg :: PagedLOD类)
  • 能够与Qt框架集成。 由于Qt提供了方便的“信号-插槽”模型,该模型大大简化并加快了C ++开发,我们广泛使用此框架来开发培训复杂的软件。 因此,我们积累了重要的代码库,这些代码库已在不同项目中重用,尤其是在基于TCP套接字的进程间通信库方面。 在视频子系统项目中使用Qt的功能似乎是一个合理的决定。
  • 要解决的任务需要足够的图像质量。

为了彻底“探究基础”并找到解决此引擎问题的方法,花了大约六个月的时间深入研究OSG功能。 结果产生的结果值得单独讨论。

4.从架构到工作原型


机车车辆训练模拟器(HTSC)的视频子系统是一个客户端应用程序,通常称为video3d-client,它执行以下功能:

  • 连接到模拟器的服务器部分的请求,服务器上的授权,随后是对加载路线的标识符的定期请求,然后是火车的当前位置。 如果从服务器端断开连接,系统将切换到待机模式以重新连接;
  • 下载选定的路线,组织动态管理渲染场景的内容;
  • 根据路线上火车的当前位置实际渲染场景

并不是说该项目是开源的,而是可以在此处找到功能齐全的技术演示的代码。 该项目包含以下模块:

  • 文件系统 -用于处理文件系统的库,提供生成配置文件和应用程序资源的路径
  • library-动态库加载器的跨平台实现。 总的来说,在与Qt集成的可能性(其中有准备战斗的QLibrary模块)的时候,拐杖仍然模糊不清
  • osgdb_dmd-一个插件,用于加载特定于DGLEngine 1.1版的格式的模型。 对于所需的内容,我将解释一下
  • route-loader是一个库,它为路由加载器提供抽象接口。 可以加载任意格式的路由
  • tcp-connection-通过TCP套接字的进程间通信库
  • 查看器 -程序的主要可执行模块
  • zds-route-loader-用于加载ZDSimulator格式的路由的插件

在设计VTPS时,出现了一个问题,即是独立开发路线格式,还是使用现有路线格式以及现有铁路模拟器的现有国内铁路路线。 幸运的是,该解决方案最终成为了封闭的专有产品ZDSimulator ,它具有针对国内机车车辆和铁路网络的特点而量身定制的特性。 尽管该项目的作者赞扬了它,但它仍然存在许多明显的缺点,但同时,它具有一种简单明了的公开路线格式。 在第一个阶段,尽管模拟器的图形部分基于开放的DGLEngine引擎,但没有抓住机会是一个罪过。 问题在于该引擎虽然正在开发( 可以在此处查看项目的当前状态),但是其当前的第二版本与ZDSimulator所基于的1.1版不兼容。版本1.1的源代码已丢失,指向它们的链接已经消失了很长时间。

通过在Web存档中进行全面搜索,可以通过在Gtihub发布DGLEngine v1.1来查找丢失的文件并进行保存该引擎使用自己的特定3D模型格式。有了引擎的来源,很容易为OSG编写适当的插件。

因此,创建HTPS的任务减少为在OSG引擎上编写软件部分。将来,计划开发自己的路线格式,因为当前格式仅允许沿主要路线移动,并且存在许多缺点,不允许重新创建许多复杂路线。

下图显示了HTPS主要类别的层次结构


路由加载器类层次结构如下所示


任何其他路由格式的加载程序都可以编写为包含从RouteLoader类继承的类的插件。在VTPS开始时,会将带有路由的目录路径传送到该路径,确定路由的格式,并动态加载相应的插件,然后执行其余的工作。

一个根本重要的细微差别是OSG引擎和Qt的集成。存在这种集成,称为osgQt此项目未使用此库,原因有两个:

  1. 不需要Qt提供的窗口控件。OSG拥有自己开发的相当完善的GUI窗口管理系统,并且没有理由将GUI围在另一个GUI上,因为osgQt主要用于将OSG查看器集成到基于Qt的GUI中
  2. osgQt会遇到一个错误-使用OpenGL上下文的操作不正确,在某些情况下,由于OSG和QGLWidget不能在Qt小部件上显示场景,因此无法在OSG和QGLWidget之间进行划分。此外,由于某些错误不会在某些系统上显示出来,因此尚无法找出原因。

有一种理解,就使用“信号插槽”的概念而言,需要与Qt集成,以确保与使用Qt的tcp-connection网络子系统进行交互,该子系统是我们设计中的事实上的标准。我真的不想依靠OSG消息传递系统并重新编写TCP客户端(甚至跨平台)。基于以下事实,找到了一种优雅的解决方案:如果我们要一个对象发送触发另一个对象的插槽的信号,则必须满足以下三个条件:

  1. 从QObject继承交互类
  2. 组织信号处理循环
  3. 创建在应用程序操作期间内存中存在的QApplication(或QCoreApplication)类的实例

在这种情况下,在任何情况下都不应该调用QApplication :: exec()来启动常规信号处理周期,这足以组织一个周期,通过调用QApplication :: processEvents()可以轻松处理信号。OSG具有这样一个周期(执行渲染的周期),并且可以创建事件处理程序,在该事件处理程序中,当渲染下一帧时引擎生成的osgGA :: GUIEventAdapter :: FRAME事件。因此,所有集成都简化为代码

qt-events.h

#ifndef QT_EVENTS_H #define QT_EVENTS_H #include <osgGA/GUIEventHandler> #include <QtCore/QtCore> class QtEventsHandler : public osgGA::GUIEventHandler { public: QtEventsHandler(){} virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa); protected: }; #endif // QT_EVENTS_H 


qt-events.cpp
 #include "qt-events.h" bool QtEventsHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) { switch (ea.getEventType()) { case osgGA::GUIEventAdapter::FRAME: { QCoreApplication::processEvents(QEventLoop::AllEvents, 100); break; } default: break; } return false; } 

main.cpp

 #include "main.h" /*! * \fn * \brief Entry point */ //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); RouteViewer viewer(argc, argv); if (viewer.isReady()) return viewer.run(); return 0; } 

之后,从QObject及其派生类继承的类可以交换信号,直到丢失脉冲。

以上所有内容允许两个月来创建HTPS的第一个工作原型。 为了演示最后发生的情况,我建议在实际路线上的实验性旅行中提供以下部分。 对于拍摄质量,我事先表示歉意-他们没有掌握智能技术


结论与结论


至少对于我们的团队而言,主要结论是,在选择用于实施该项目的技术时没有“灰子弹”。 积极销售的游戏引擎并不总是适合解决特定任务,包括可视化建模技术系统的结果。 并且如果它们合适,那么就项目开发和维护所花费的精力而言,它们并不是最佳的。

一个非常好的,而且最重要的是免费的,OSG图形引擎,实际上在我们的国家没有社区,真是令人遗憾。 为了解决此问题,我在此处撰写了有关资源一系列文章 (收集了到或多或少足够的信息资源的所有链接,包括俄语)。 另外,作为描述OSG基本原理的文档,我也可以提供此博客 。 我希望有人会发现此信息有用。

关于HTSC,这方面的工作仍在继续。 在不久的将来,仍有许多重要任务需要解决。

感谢您的关注!

(c)创新能力发展中心

Source: https://habr.com/ru/post/zh-CN436276/


All Articles