自制游戏引擎 - 图形API
游戏引擎RHI目前选用的是bgfx
- Pros
- 可以参考的代码比较多
- Real-Time Polygonal-Light Shading with Linearly Transformed Cosines论文作者的原文实现也用了bgfx
- 论文作者博客,包含可运行的例子程序 - https://eheitzresearch.wordpress.com/415-2/
- bgfx作者希望有人帮忙把这个例子换个小场景,然后port进来 - https://github.com/bkaradzic/bgfx/issues/1609
- Github上的LightMap开源烘焙工具XAtalas,也是基于bgfx作为3D查看器
- 我的世界也使用了bgfx作为图形API,对bgfx的质量有一定保证
- 更多例子可以查看Github bgfx的README.md
- Real-Time Polygonal-Light Shading with Linearly Transformed Cosines论文作者的原文实现也用了bgfx
- 兼容性,基本上所有图形API,平台都有支持,而且是经过测试的
- 可以参考的代码比较多
- Cons
- 包袱多,对新旧两三代图形API都做了支持,抽象到同一套API中,让bgfx的上层API看起来太high level,与现代图形API违背
- Diligent Engine会比较现代化,不支持过于陈旧的图形API - https://github.com/DiligentGraphics/DiligentEngine
- 虽然bgfx API是high level的,但实际上直接拿这些API去写图形效果会很累,仍然需要再次进行high level抽象
- 包袱多,对新旧两三代图形API都做了支持,抽象到同一套API中,让bgfx的上层API看起来太high level,与现代图形API违背
bgfx入门
- 通过GENie编译
- –with-windows指定使用的Windows SDK版本,–with-examples可以把bgfx的几十个参考例子生成出来,–with-tools可以生成bgfx工具层项目,比如基于glsl的shader跨平台预处理器,模型/贴图的二进制编译工具
1
2cd "bgfx"
"../bx/tools/bin/windows/genie.exe" --with-windows=10.0 --with-examples --with-tools vs2022`
- –with-windows指定使用的Windows SDK版本,–with-examples可以把bgfx的几十个参考例子生成出来,–with-tools可以生成bgfx工具层项目,比如基于glsl的shader跨平台预处理器,模型/贴图的二进制编译工具
- 打开生成的.build/projects/vs2022/bgfx.sln,工程分为三块
- libs
- 默认通过静态库的形式链接bgfx等库函数,也可以在make时指定动态库的形式
- tools
- shader/texture/model资源编译工具
- examples
- example-common是一个简单的例子程序框架,方便编写其他例子
- 第三方库
- dear-imgui :一个旧版ImGui版本,被bgfx修改后集成
- meshoptimizer :模型优化工具,可以优化顶点,索引数据的布局,模型自动减面
- 第三方库
- 其他example工程代码是通过继承一个example-common提供的带有init,shutdown,update三个纯虚函数的接口类实现的
- example-00-helloworld
- 在init中,bgfx::init函数负责了图形API初始化的所有工作
- 举一些重要的Init结构体参数做说明
- type是RendererType::Enum枚举类型,罗列了bgfx支持的所有图形API类型,每一个类型都对应了libs/bgfx/src目录下的一份渲染后端代码.h/.cpp。比如DirectX11,就对应了renderer_d3d11.h和renderer_d3d11.cpp
- vendorId可以指定使用某一个品牌的显卡,或者是软光栅模拟;如果同一品牌的有两张显卡,那么可以用deviceId来指定用哪一张
- capabilities - 指定显卡特性开启的mask
- debug和profile - 开发期间打开,输出更多的调试信息到Output窗口
- platformData - 平台相关参数,比如想把图形API渲染的画面输出到一个Windows窗口上,那么可以指定platformData.nwh(native window handle)为该Windows窗口的句柄HWND。我个人推荐长命名的方式,nwh这类省略式的命名方式在大规模的工程中增大了理解难度,比如dir可以是direction,也可以是directory
- resolution - 指定渲染目标的FrameBuffer尺寸,数量等
- limits - 对Command Buffer,以及模型相关的Vertex Buffer/Index Buffer做限制
- Command Buffer是现代图形API里的概念,主体思想是CPU和GPU的交流就像客户端和服务器异步通信一样,每一个图形API操作都可以理解成是发送一条命令/消息,进行一次图形操作的背后是多条图形API的组合。因为GPU算力是远大于CPU的,所以当CPU单核提交渲染命令时,GPU可能会因为CPU布置任务太慢太少而闲置下来。这种情况下,现代图形API的设计是每一帧的画面渲染需要的命令由多个线程去提交,每个线程都拥有一个Command List,去塞该线程提交的Command,然后一帧命令准备完毕,再从每个线程的Command List汇总所有Command塞到图形API的Command Buffer中,一次性提交给GPU,等待绘制
- 在bgfx的概念里,bgfx::submit操作会将一次物体绘制需要的资源句柄收集起来,对应一个draw call;每个渲染线程可以分配一个bgfx::encoder,这个encoder就记录着draw call需要的资源句柄。等待bgfx::frame的调用,去一次性通过图形API提交渲染数据到GPU上
- allocator可以指定一个定制化的内存分配器,但需要保证线程安全
- 举一些重要的Init结构体参数做说明
- 在init中,bgfx::setViewClear负责每帧设置清屏的初始颜色
- bgfx的view是一个重要的概念,不同于常规理解的viewport,这里的view是一个draw call队列,每个view有自己的view id,也就是bgfx::setViewClear的第一个参数,你还会看到很多bgfx api要求指定view id,比如前面提到的bgfx::submit创建draw call,它就需要指定一个view id,来把draw call创建到某一个draw call队列里,也就是view。
- view的作用有很多,比如图形引擎经常需要做的一件事情是对draw call对象进行各种排序,来达到渲染目的。比如说透明物体渲染,那么就可以把所有透明物体塞到一个view里,然后通过bgfx::setViewMode去指定队列内draw call优先级,没错,draw call队列是一个优先队列
- view也可以用于区分不同目的draw call,保持渲染模块的整洁,比如ingame GUI的渲染可以指定ViewId为0,3D场景的不透明物体渲染指定ViewId为1,透明物体渲染指定ViewId为2,…,至多可以指定0~255一共256个view
- 在init中,imguiCreate负责ImGui的初始化
- 跟进到example-common里的ImGui框架,你会发现ImGui API调用产生的绘制数据在框架内转译成了bgfx API调用,再自行塞到前面提到的bgfx::encoder当中,等待bgfx::frame提交
- init背后的事
- 图形Device以及Context的创建
- FrameBuffer创建完了之后,SwapChain的设置
- shutdown时,注意先销毁ImGui把bgfx::encoder释放掉,最后再销毁bgfx
- update时,imgui API的调用会让ImGui内部生成DrawCall,最后在example框架中会对接bgfx的各种设置材质,Vertex Buffer/Index Buffer的API,最后再由bgfx::frame提交到GPU
- 在init中,bgfx::init函数负责了图形API初始化的所有工作
- example-05-instancing : gpu instance渲染
- example-12-lod : 一种edge collapse方式的模型自动减面算法
- example-13-stencil : 模板测试
- example-17-drawstress : 多个渲染线程
- example-27-terrain : 地形
- example-32-particles : GPU粒子实现
- example-37-sky : 大气散射,天光
- example-38-bloom : 后处理bloom
- example-46-fsr : AMD FSR超采样
- TBD
- example-common是一个简单的例子程序框架,方便编写其他例子
- libs
bgfx源码剖析
TBD
其他RHI
- The-Forge - https://github.com/ConfettiFX/The-Forge
- NVRHI - https://github.com/NVIDIAGameWorks/nvrhi
- Ominiverse
参考资料
- SakuraEngine运行时(一):RHI和WASM - https://bkaradzic.github.io/bgfx/tools.html#shader-compiler-shaderc
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.