电脑故障问答网

 找回密码
 立即注册
查看: 95|回复: 1

从零开始的场景编辑器(一):Qt和DX9的结合

[复制链接]

2

主题

2

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2022-11-27 16:18:37 | 显示全部楼层 |阅读模式
很抱歉第一篇正文久拖了那么久,最近一方面是个人事情比较多,另外一方面我也一直在思考如何组织我这个专栏比较好。由于它是一个学习笔记一样的东西,我比较倾向于按照coding的顺序(因为还没写完)来讲,但是那样就会导致关注的方面太多,不容易看清楚思路和结构。但是不按照这个,感觉代码没写完也不好系统的讲。纠结良久,最后打算还是按照进度来讲,但是在每一篇后面加一个独立的副标题,以增加独立性。   
Qt

上一篇 说到要开发一个场景编辑器,愿景很美好,但是手上什么都没有。我个人感觉开发工作有些像在搭积木,而且很需要一个正反馈(有些像玩游戏)。因此首先我们需要一个能马上拿到手上编译通过运行的"主代码"来当作积木玩具的主体。之前提到了GUI 界面将采用Qt。那么现在最简单的方法就是打开 QtCreator 新建一个工程。然后编译运行得到一个主窗口。   
Qt默认的生成的东西有以下一些:   

  • .pro 的工程文件
  • mainwindow.h .cpp 主窗口的类文件
  • main.cpp 文件
  • ui 文件
  但是我们的工程不仅仅是Qt程序,这里如果用Qt的qmake 每次prase .pro文件感觉会比较抓狂,而且QtCreator 虽然有Qt的文档加持,其他方面就比不上带VA插件的VS了。因此,我们的编译工具和coding的IDE 需要重新选。想来想去,我选择了 使用 CMAKE 作为编译工具,刚好Qt中有cmake 的支持。  
set(CMAKE_AUTOMOC ON)
...
find_package(Qt5 COMPONENTS Core Widget REQUIRED)
...

target_link_libraries(Editor Qt5::core Qt::Widgets ...)只要在环境变量中正确设置Qt的PATH,在CMakeLists.txt中添加上面的代码就可以把Qt的依赖加入工程中。
接着在CMakeLists.txt文件下用命令行执行
cmake .在windows 下就会生成VS的sln工程文件(需要安装VS2017或者其他版本)。接下来就可以用VS愉快的coding了。   
Qt + DX9 (GameBryo)

  我们的渲染引擎是基于Dx9的,而Qt底层使用的是OpenGL。熟悉DX9和GameBryo的朋友应该知道,他们在初始化的时候都需要HWND类型的窗口Handle来作为要在哪个窗口显示的参数。大概像下面这样.
//D3D
g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice )
//GB
m_spRenderer = NiDX9Renderer::Create(0, 0,
        NiDX9Renderer::USE_NOFLAGS, m_hWND, NULL);
  Qt程序毕竟也是windows程序,因此提供了winId()接口来获取windows窗口的Handle。解决了DX9的初始化的问题还不够,还需要对QWidget类做一些配置 :
class D3DWidget : public QWidget
{
public:
    QPaintEngine * paintEngine() const
    {
        return nullptr;
    }
    D3DWidget(QWidget * parent) :
        QWidget(nullptr)
    {
        setAttribute(Qt::WA_PaintOnScreen,true);
        setAttribute(Qt::WA_NativeWindow,true);
    }
    //完成渲染循环 etc
    virutal void paintEvent(QPaintEvent * event) ;
    //获取窗口 Handle
    HWND GetWinId() { return (HWND)this->winId();}
    ...

}
主要是重写 paintEngine 和 paintEvent 两个方法,并且需要设置Widget的Atrribute 。 paintEngine 中因为现在不用OpenGL了,所以直接返回nullptr就好,paintEvent则是放渲染引擎渲染循环的地方。一般情况下是这样的:
void D3DWidget :: paintEvent(QPaintEvent * event)
{

    do_something();
    // render 渲染
    m_pkRender->Render();

    //调用 QWiget的update 来完成更新
    update();
}
测试的时候设置一下Dx9的背景色,将其加入D3DWiget中,然后在mainwindow 中添加 D3DWiget的实例.一切顺利的话就能看到带背景色的Qt窗口了。至此,理论上使用DX9渲染的图形就能出现在Qt的widget中了。这样其他UI界面直接使用Qt,而渲染直接使用DX9(GB)就好了。   
坑(题外话)

  在使用Qt的过程中,因为觉得用C++写UI比较蠢,我短暂的考虑过PyQt 和 Qt 的Qml。 PyQt 使用的是python ,考虑到D3Dwiget 这个组件似乎没有办法用脚本语言来实现,铁定是C++,这个时候就需要考虑C++ Qt和PyQt的结合问题。。想来想去觉得太蠢了,因此作罢。 而Qml是类似javascript用来快速定义界面和界面逻辑的语言,并且Qt官方的文档和教程很多,跟C++的结合也比较容易,看起来是一个很好的选择。但是实际操作和文档了解了一番。。Qml的界面居然是基于 QGrpahics那一套实现的,而不是传统的QWidget。。这就给基于QWidget的D3DWidget 和 Qml界面的结合造成了比较大的困难。。考虑到UI其实不是整个工程的重点。。干脆就全都用C++了。
回复

使用道具 举报

0

主题

5

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2025-3-24 23:51:02 | 显示全部楼层
传说中的沙发???哇卡卡
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

云顶设计嘉兴有限公司模板设计.

免责声明:本站上数据均为演示站数据,如购买模板可以上DISCUZ应用中心购买,欢迎惠顾.

云顶官方站点:云顶设计 模板原创设计:云顶模板   Powered by Discuz! X3.4© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表