现在的位置: 首页 > 综合 > 正文

Qt—在Qt窗口中显示DirectX11的方法

2013年12月19日 ⁄ 综合 ⁄ 共 3803字 ⁄ 字号 评论关闭

这段时间正在做DX11的图形渲染,打算做一个模型动画预处理的编辑界面,对各种C++ GUI SDK的选择,MFC在Windows中本来是首选,但是自己并不是很熟悉MFC编程,所以我考虑使用我比较熟悉的Qt来做界面,从网上搜索使用Qt窗口显示DX的方法,经过一番尝试大致也找到了具体的做法。

 

环境:Qt5.0.1 + VS2010 + DirectX11

 

在Direct3D 11创建渲染设备里面的 IDXGISwapChain*swapChain_;中指定D3D11设备的输出窗口swapChainDesc_.OutputWindow 指定为Qt窗口的HWND即可,其他的地方与正常创建设备一样。

 

具体步骤如下:

创建一个Widget类

class D3DRenderWidget : publicQWidget
{
    Q_OBJECT
 
public:
    D3DRenderWidget(QWidget *parent = NULL);
    ~D3DRenderWidget();
 
    virtualQPaintEngine* paintEngine()const { return NULL; }
 
protected:
    virtual void resizeEvent(QResizeEvent *e);
    virtual void paintEvent(QPaintEvent *e);
};

然后在D3DRenderWidget的构造函数中,添加窗口的两个属性。并加入一个QTimer来驱动这个Widget的painEvent事件一直运行。

D3DRenderWidget::D3DRenderWidget(QWidget*parent)
    : QWidget(parent)
{
    setAttribute(Qt::WA_PaintOnScreen, true);
    setAttribute(Qt::WA_NativeWindow, true);
 
    QTimer* timer = newQTimer(this);
    connect(timer, SIGNAL(timeout()),this,SLOT(update()));
}

接下来就可以创建设备了,找到这个Widget的HWND,并将这个HWND用作去D3D11设备的创建。

如何得到这个Widget的HWND呢?在网上搜了下,在Qt5以上,主要下面两种方式:

一个是直接将Widget中的WinId()方法返回的值强制转换为HWND

hwnd = (HWND)WinId();

另外一种是使用下面的函数:

    staticQWindow* windowForWidget(const QWidget* widget)
    {
        QWindow* window =widget->windowHandle();
        if(window)
            returnwindow;
        constQWidget* nativeParent = widget->nativeParentWidget();
        if(nativeParent)
            returnnativeParent->windowHandle();
        return0;
    }
 
    HWND getHWNDForWidget(const QWidget* widget)
    {
        QWindow* window =windowForWidget(widget);
        if (window&& window->handle())
        {
            QPlatformNativeInterface* interface =QGuiApplication::platformNativeInterface();
            returnstatic_cast<HWND>(interface->nativeResourceForWindow(QByteArrayLiteral("handle"), window));
        }
        return0;
    }

这里我使用的是第一种方法,因为第二种方法在当Widget作为某个窗口的子窗口时候会得不到这个HWND,具体情况不知道是怎么回事。

接下来就是创建D3D11的设备了,创建的步骤跟一般的方法一致,只是将这个窗口的HWND传入IDXGISwapChain中即可。

bool D3DRenderWidget::createDevice()
{
    HRESULT re;
    UINT createDeviceFlags = 0;
#if defined(DEBUG) ||defined(_DEBUG)
    createDeviceFlags |=D3D11_CREATE_DEVICE_DEBUG;
#endif
    D3D_FEATURE_LEVEL featureLevel;
    HRESULT hr = D3D11CreateDevice(
        0,
        m_d3dDriverType,
        0,
        createDeviceFlags,
        0,
        0,
        D3D11_SDK_VERSION,
        &m_d3dDevice,
        &featureLevel,
        &m_d3dImmediateContext);
 
    if(FAILED(hr))
    {
        MessageBox(0, L"D3D11CreateDeviceFailed.", 0, 0);
        return false;
    }
 
    if(featureLevel != D3D_FEATURE_LEVEL_11_0)
    {
        MessageBox(0, L"Direct3DFeature Level 11 unsupported.", 0, 0);
        return false;
    }
 
    re =m_d3dDevice->CheckMultisampleQualityLevels(
        DXGI_FORMAT_R8G8B8A8_UNORM, 4,&m_4xMsaaQuality);
    if(FAILED(re)) returnfalse;
 
    assert(m_4xMsaaQuality > 0);
 
    DXGI_SWAP_CHAIN_DESC sd;
    sd.BufferDesc.Width = width();
    sd.BufferDesc.Height = height();
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format =DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.ScanlineOrdering =DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling =DXGI_MODE_SCALING_UNSPECIFIED;
 
    if(m_enable4xMsaa)
    {
        sd.SampleDesc.Count = 4;
        sd.SampleDesc.Quality = m_4xMsaaQuality- 1;
    }
    else
    {
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
    }
 
    sd.BufferUsage  = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount  = 1;
    sd.OutputWindow = (HWND)winId();
    sd.Windowed     =true;
    sd.SwapEffect   = DXGI_SWAP_EFFECT_DISCARD;
    sd.Flags        =0;
 
    IDXGIDevice* dxgiDevice = 0;
    re = m_d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
    if(FAILED(re)) returnfalse;
 
    IDXGIAdapter* dxgiAdapter = 0;
    re = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter);
    if(FAILED(re)) returnfalse;
 
    IDXGIFactory* dxgiFactory = 0;
    re = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
    if(FAILED(re)) returnfalse;
 
    re =dxgiFactory->CreateSwapChain(m_d3dDevice, &sd, &m_swapChain);
    if(FAILED(re)) returnfalse;
 
    safe_release(dxgiDevice);
    safe_release(dxgiAdapter);
    safe_release(dxgiFactory);
}

将这个Widget放入QMainWindow的centerWidget进行显示。

最后显示了Qt5WithD3D11的蓝色窗口~_~

 

程序代码:http://download.csdn.net/detail/hgplan/5267421

(PS: 程序运行前,要设置DX的include路径和lib路径~)

参考:

http://jholewinski.org/blog/direct3d-11-with-qt-4/

https://bitbucket.org/jholewinski/qt4-d3d11

http://stackoverflow.com/questions/14048565/get-hwnd-on-windows-with-qt5-from-wid

抱歉!评论已关闭.