游戏引擎开发新感觉!引擎架构篇
关注的人比想象的要多,很开心呐,就快点介绍下引擎的组成部分吧。引擎内容是真的多,光想想就很痛苦。为了保持好心态,预先做一些规划还是需要的。这里就盗milo大神翻译的《游戏引擎架构》的图了,我画了些框框,表示现在会覆盖的功能。
游戏引擎架构大致如上图所示,具体想了解的请买《游戏引擎架构》原书吧!很不错哦。
第一阶段的开发工作主要集中在绿色部分,差不多是渲染相关的模块。毕竟目前游戏引擎最关键的还是渲染,打好渲染的基础,后面的功能才能顺利地加入。这个开发量已经非常艰巨了,我也不知道能不能完成。希望能实现出来,完不成就要鸽了。。。
蓝色的是第三方库,它们会省我们很多人年的工作量,这些都要自己开发的话,真的没完没了了。
下面简单介绍下用到的库,基本是一些罗列,排版较乱,大致看下就行。
第三方软件开发包
stl,boost,d3d12,vulkan,unity
这里重点提一下stl和boost,他们会是我们的核心依赖。绝大部分的功能都直接调包了,只要stl和boost支持,基本一定会用。这主要有以下几点考量。
- 通用性。功能很多,能解决各类问题。一般能想到的基本都在里面。
- 高质量。作为标准库和准标准库,代码质量有保证。bug少,安心。
- 低成本。boost库专业维护人员众多,削减了大量的开发与维护成本。
- 易移植。没有特别的轮子,大家共有的代码基。有共同语言,借鉴起来相对容易。
- 性能好。库的开发者做了大量优化。虽然泛用容器肯定比不上专用容器,但总体还是ok的。
d3d12是我们的主力图形api,现在基本是照搬d3d12的架构,不过我们也会参考下vulkan。vulkan的设计也是相当不错的,api和d3d12稍微有些区别,不过区别不大。
unity也会用到啦。借鉴,嗯,你们懂的。
平台独立层
平台检测:boost::config,boost::version
现在基本是windows开发,我还没怎么用过。在遥远的未来开发android的时候,也许会用上。
原子数据类型:std::atomic,boost::lockfree,tbb
原子操作我们会用到一些,主要是有些数据结构会用到多线程refcount,这时就需要atomic_int了。我们的多线程架构完全基于无锁队列,所以需要lockfree、tbb的帮助。
集合和迭代器:stl,boost::container,boost::multi_index,boost::graph
通用容器我们就不开发啦,虽然通用容器没有那么针对游戏、性能不够优秀,先不优化了。
文件系统:std::filesystem
操作文件特别好用,工具经常会用到,runtime不一定。
网络传输层:boost::asio
好吧,我们并没有网络功能。不过以后要用的话,还是asio。
高分辨率时钟:std::chrono
时钟开发也很麻烦,希望high_resolution_clock够用,不行的话要另行开发。
线程库:std::thread,boost::asio
我们的多线程框架基于asio,基本会形成回调地狱。主要是我对协程的掌握非常一般,等c++20出了再学吧。
小结:可见STL和boost基本覆盖了平台独立层,我们就看下这两个跨平台的库是不是真的跨平台吧。
核心系统
断言:gsl::assert
Guidelines Support Library 是C++官方的辅助库,里面有Expects和Ensures分别检测pre-condition和post-condition。是assert的更好替代,推荐使用。
单元测试:boost::test。我们会尽量添加单元测试,但是我又很懒,可能用的不多。
内存分配:c++默认分配器
注意我们没有使用高性能的tbb、tcmalloc等分配器。原因有两点:
- 减少依赖。依赖第三方内存分配器,容易引入更多的bug,使得程序更难调试,我们不太希望有意外的惊喜。性能对我们这种没人用的引擎,没有那么重要,哈哈哈。
- 内存预分配。我们会尽量预先分配好内存,这样分配器性能就没有那么重要了。
数学库:eigen
eigen是一款非常好的跨平台数学库,无论是易用性、工程性、性能、功能、扩展能力、跨平台性都是顶尖的。被广泛运用到PCL、OpenCV、Meshlab等优秀的类库中,是久经考验的一款数学库。eigen是我们的核心依赖,会用到Dense、Geometry、Spline等功能。
字符串与散列字符串标识符:std::string,std::string_view,boost::algorithm::string,boost::flyweight
std::string饱受诟病,用起来确实够难受的,不过配合boost::algorithm还是可以一战的。flyweight能方便的制作string的handle,减少内存分配,有跨dll能力,也许会用到。
调试用打印和日志:boost::log
这里的问题是boost::log必须启用rtti,但引擎的runtime又不会开启rtti,所以就暂时就不打log了。这里就体现c++为什么需要zero-overhead abstraction了,功能有传染性的话,那就只有不用了。
本地化服务:std::locale,std::codecvt
c++的locale和codecvt是两朵巨大的奇葩,标准变了又变,我现在已经混乱了。等c++20引入了char8_t再说吧,先不解决locale问题了。
引擎配置:boost::property_tree,boost::program_option
一个读写配置、一个读写控制行命令,很省事。现在用的不多。
随机数生成器:std::random,boost::random
都可以用,速度一般。
曲线与曲面库:unsupported.Eigen.Spline
这个我还没开始用,不过有这个功能还是好的。曲面暂时不解决。
对象句柄/唯一标识符:boost::uuid
uuid就是一般的guid,我们的资源索引基本会用uuid描述。资源模块之后的章节会介绍。
异步文件io:std::filesystem,std::iostream,boost::asio
这三个加起来,可以解决异步文件io的问题,就是需要一点开发。
场景图/剔除优化
空间剖分:boost::geometry::index::rtree
空间索引,暂时不用开发octree/bvh,不用开发的功能就是好的功能!
小结
以上这些模块,就不一一详细介绍啦,官方文档又全又好。主要是比我的理解准确多了,第一手资料比较可靠!
总体来讲,平台独立层和核心系统是不需要开发的,削减了一小半的工作量。这让我们可以把精力集中到游戏资源、底层渲染器上,这两个是目前的重头戏。
下次会介绍渲染引擎的设计,个人觉得很有趣(奇葩)哦。