记录使用vulkan结合Objectarx开发的过程(一)——Vulkan在Qt中的实现

文章介绍了如何在Qt环境下集成和使用Vulkan进行图形渲染,包括设置开发环境(VS2017,Vulkan1.3.236.0,Qt5.14.2),利用Qt的QVulkanInstance等类,以及自定义实现以适应复杂渲染需求。在QWindow的生命周期事件中初始化Vulkan资源,处理窗口大小变化、隐藏和关闭等事件,确保Vulkan渲染的正确显示。
摘要由CSDN通过智能技术生成

题外话

以往学习也好工作也好,在处理三维的时候都是借助现成的开源库搭建对应的三维场景,限于时间因此对这些开源库底层的细节处理鲜有关注,此次借助学习vulkan的机会做一个简易的显示应用并记录下整个过程中的些许细节片段。

开发环境

开发环境:VS2017+Vulkan1.3.236.0+Qt5.14.2+ObjectArx2017。
关于环境搭建部分在这里不在展开讨论,需要说明的是选择VS2017是因为后续考虑结合Objectarx2019/2020来做些简单的小工具,而Objectarx2019/2020对应的开发环境为VS2017。另外关于Qt的版本,在5.10之后的版本才支持vulkan,并且Objectarx中使用的界面是MFC,为了将Qt嵌入MFC中需要对Qt进行框架迁移,这个在后续的与Objectarx结合时再做详细记录。

向Qt中添加Vulkan

Qt自带的处理类

Qt本身实现有相应的类来支持Vulkan,例如QVulkanInstance、QVulkanWindow、QVulkanWindowRenderer、QVulkanWindowPrivate等,具体的实例可以参照Qt目录Examples\Qt-5.14.2\vulkan下的具体代码。

关于自身对Qt-vulkan相关类的选择

由于Qt自身实现的QVulkanWindowRenderer及QVulkanWindowPrivate实现的仅为基本的渲染功能,如需要更复杂的渲染需求时仍需要对其进行改造,因此除了使用了QVulkanInstance外其余的就直接选择自己实现好方便后续修改。

实现在Qt中绘制Vulkan渲染结果

Qt界面中实现vulkan的流程同OpenGL相似,可参考QVulkanInstance类的帮助文档,但文档仅含显示的主要流程,窗口大小改变、窗口最小化及关闭窗口等处理需要自行补充,以下是整个过程的简要记录:

  1. 初始化vulkan实例及设置QWindow的surface和instance

实现一个QWindow的派生类,此次练习对应的派生类为MLINView3D,在派生类的初始化函数中主要做两件事,一是设置QWindow支持vulkan,二是创建一个vulkan实例对象,参考代码如下

	//! 描述:验证回调函数
    bool DebugFilter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object,
   		size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage)
   {
   	std::cout << pMessage << std::endl;
   	return false;
   }
   //---------------------------------------------------------------------------------------
	setSurfaceType(QSurface::VulkanSurface);//设置窗口支持vulkan
   	m_VkIns.setLayers(QByteArrayList()//添加需要开启的验证,当发布程序时可删除
   		<< "VK_LAYER_LUNARG_parameter_validation"
   		<< "VK_LAYER_LUNARG_object_tracker"
   		<< "VK_LAYER_LUNARG_core_validation"
   		<< "VK_LAYER_LUNARG_image"
   		<< "VK_LAYER_LUNARG_swapchain"
   		<< "VK_LAYER_KHRONOS_validation");
   m_VkIns.installDebugOutputFilter(DebugFilter);//开启验证层并设置对应的回调函数
   if (!m_VkIns.create())//创建对应的vulkan实例
   {
   		qDebug() << "Failed to create instance";
   }
   setVulkanInstance(&m_VkIns);//设置QWindow支持的vulkan实例`
  1. 在QWindow的exposeEvent()中实现对vulkan渲染资源的初始化,相关参考代码如下:
  	if (isExposed()) 
  	{
  		if (m_State == STATE0)//标记初始状态,表示没有任何vulkan实现
  		{
  			m_State = STATE1;
  			//初始化vulkan资源,如Swapchain、framebuffer、pipeline、renderpass等所有的渲染资源
  			m_pVulkanPrivate->initVulkanInstance(m_VkIns.vkInstance());
  			m_pVulkanPrivate->initShapeResource();
  		}
  	}
  1. 在QWindow的resizeEvent()事件中实现对交换链的重建:
    每当屏幕大小变化时需要重建交换链中涉及的资源,其主要为与屏幕大小相关的图片、视图、交换链、帧缓冲等。
void MLINView3D::resizeEvent(QResizeEvent* pEvent)
{
   if (m_State == STATE0)
   {
   	  return;
   }
   QSize winSize = this->size();
   m_pVulkanPrivate->recreateSwapChain();//重建交换链相关资源
   m_Camera.SetOrthoProjection(this->width(), this->height(), m_Camera.m_ProjBoxSize.x(), 
   		m_Camera.m_ProjBoxSize.y(), m_Camera.m_NearPlane, m_Camera.m_FarPlane);
   m_pVulkanPrivate->updateProjectionUniformBufferData();
   m_pVulkanPrivate->drawFrame();//更新屏幕
}
  1. 实现QWindow::event()事件
bool MLINView3D::event(QEvent* pEvent)
{
  switch (pEvent->type())
  {
  	case QEvent::UpdateRequest: //处理刷新事件
  		m_pVulkanPrivate->drawFrame();//对当前场景进行渲染
  		break;
  	case QEvent::Hide: //处理隐藏事件,如最小化
  		m_pVulkanPrivate->hideOrShow(false);//停止渲染
  		break;
  	case QEvent::Show: //处理显示事件
  		if (m_pVulkanPrivate->canDraw())
  		{
  			m_pVulkanPrivate->hideOrShow(true);
  			requestUpdate();//请求绘制下一帧
  		}
  		break;
  	case QEvent::PlatformSurface:
  		if (static_cast<QPlatformSurfaceEvent *>(pEvent)->surfaceEventType() == 
  				QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)//处理窗口关闭事件
  		{
  			m_pVulkanPrivate->cleanup();//清楚vulkan资源
  			m_State = STATE0;
  		}
  		break;
  }
  return QWindow::event(pEvent);
}
  1. 将MLINView3D作为widget组件添加到相应的界面位置,
MLINVK3D::MLINVK3D(QWidget *parent) : QMainWindow(parent)
{
   ui.setupUi(this);
   QSplitter* pMainSplitter = new QSplitter(Qt::Horizontal, nullptr);
   ui.horizontalLayout->addWidget(pMainSplitter);
   mNavigation = new NavigationBar(pMainSplitter);//场景节点窗口
   QSplitter *pRighterLitter = new QSplitter(Qt::Vertical, pMainSplitter);
   mView3D = new MLINView3D();//创建一个支持vulkan的QWindow对象
   QWidget* pView = QWidget::createWindowContainer(mView3D);//将QWindow对象生成对应的Widget
   pRighterLitter->addWidget(pView);//将支持vulkan的组件添加到窗口的图像显示区域
   mCmd = new CommandBar();//命令行窗口
   pRighterLitter->addWidget(mCmd);
   pMainSplitter->setStretchFactor(0, 2);
   pMainSplitter->setStretchFactor(1, 8);
   pRighterLitter->setStretchFactor(0, 8);
   pRighterLitter->setStretchFactor(1, 2);
}

运行效果

运行界面结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值