Vulkan就一种图形接口,由于本身不提供异常处理,所以需要开发者自己来定位错误信息以及保证API接口的正确使用。
要想开发一个最简单的完整demo,也要比OpenGL要复杂的多,整理一下,大概有不到20个步骤:
- 创建Instance
- 创建Surface
- 创建Device
- 创建Swapchain
- 创建RenderPath
- 创建DescriptorSetLayout
- 创建Pipeline
- 创建CommandPool
- 创建Resource
- 创建FrameBuffers
- 创建TextureSampler
- 创建VertexBuffer
- 创建UniformBuffer
- 创建DescriptorPool
- 创建DescriptorSet
- 创建CommandBuffers
- 创建SyncObjects
- 帧循环DrawFrame
再加上纹理的处理,基本上也就20个了。
为了加深理解,动手完成一个绘制三角形的例子,只设置颜色,不涉及纹理。具体的参考文档:Vulkan编程指南.pdf
一、创建一个Qt的工程,工程名为:QtVulkan
按默认配置,一路“Next”直到创建完成工程,其工程目录为:
这时,创建完成了一个带有QMainWindow窗口的工程。运行界面如下:
如果运行不起来,就检查一个工程的配置,这属于基本的Qt工程创建,就不在细说了。
还需要一个QWidget还填充QMainWindow的中央区域,也用来显示三维的场景。之前刚接触vulkan时,继承于Qt中的原生QWidget,用来显示vulkan绘制的对象。记得当时是加载了一张纹理,显示时,总是很模糊。不知道是QWidget本身显示就是模糊,还是由于代码没有写好。
现在为了和OpenGL保持一致,添加SceneWidget类,继承于QGLWidget,需要说明一下,这个版本已经比较老了,Qt的新版本中,已不再使用QGLWidget创建OpenGL的场景了。
向工程中添加SceneWidget类:
在类里添加void Init()和void UnInit()两个公有函数。以后会在Init函数中添加关于vulkan的生成函数,并在UnInit函数中添加清理vulkan资源的代码。
添加一个QTimer计数器,通过计数器来更新vulkan的场景。
添加两个槽函数,一个DrawFrame,与计数器的timeout信号相联,对场景进行刷新;一个继承于父类的resizeEvent事件,适配窗口的大小尺寸的变化。
在SceneWidget的构造函数里,添加代码,connect,将计数器信号与DrawFrame相联。再启动计数器。
SceneWidget头文件的代码如下:
SceneWidget.cpp中,除了构造函数,其它的函数都为空函数:
将SceneWidget嵌入到QtVulkan中:
在QtVulkan的头文件中包含SceneWidget的头文件,并添加一个成员变量:
在构造函数中,new中sceneWidget的对象,嵌入到主窗口的中央区域;并调用Init函数,在析构函数中,调用SceneWidget的UnInit函数。
QtVulkan.cpp的代码如下:
还需要将对应的库,添加到工程的环境里。这里用的是Qt5的版本,所以添加Qt5OpenGL.lib、Qt5Widgets.lib、Qt5Core.lib、Qt5Gui.lib,并将对应的动态库(windows系统是dll,Linux系统是so)放到对应的目录中。为了可以看到打印的信息,我们需要将的系统中的子系统,由窗口系统改为未设置,这样系统运行时,会弹出一个黑窗口,里面显示出程序中的打印的信息。
最后运行程序,能看到如下窗口,说明工程已经正常运行了。