【问题标题】:DirectX11 rendering in QT window without losing other widgets在 QT 窗口中进行 DirectX11 渲染而不会丢失其他小部件
【发布时间】:2018-05-07 17:46:40
【问题描述】:

我正在使用 DirectX 渲染到我的 QT 窗口,在我开始添加控件之前效果很好。然后当 directx 覆盖它们时它们会闪烁。 winforms 中的解决方案是在表单的 OnPaintBackground 中进行渲染,但我在 QT 中没有找到等价物。有没有类似的方法或者可以以更好的方式完成?

我正在考虑渲染为纹理,然后以某种方式将其转换为像素图,然后我在paintEvent() 中进行绘制。

能够将按钮、面板和其他控件放置在正在呈现的内容之上(实时)对我来说很重要。

编辑。

Sergio Monteleone 的回答几乎有效,控件上的闪烁消失了。我在代码中更改了控件的父级并将其设置为主窗口而不是 QFrame。但是现在如果我在控件之间快速移动鼠标,我会在控件之间得到一个奇怪的灰色框。

PushButton 后面和 GroupBox 上方的灰色矩形仅在几分之一秒内可见。知道这是为什么吗?

编辑 2.

我改变了问题的主题来描述实际问题,而不是一个解决方案。

【问题讨论】:

    标签: c++ qt qt5 directx-11


    【解决方案1】:

    我假设您正在使用 QWidget 的本机 hWnd 使用 DirectX 进行绘图。如果是这种情况,其他 Qt 控件会闪烁,因为当小部件重新绘制自身时,它也会导致完整的背景更新。然后,您使用 DirectX 在该表面上进行绘制,丢弃 Qt 控件迄今为止绘制的任何内容。

    那么为什么它们会闪烁而不是完全消失呢?

    QWidget 在内部使用双缓冲(查看文档here)。 所以这真的取决于Qt后台缓冲区何时失效。

    不过,您可以使用一个简单的技巧:将 QFrame 添加到窗口,将 Qt 控件放在其顶部,然后使用框架的 hWnd 作为 DirectX 目标。此外,您可能需要将该 QFrame 的 autoFillBackground 属性设置为 false。这应该允许您渲染到背景。

    【讨论】:

    • 谢谢!它几乎可以工作,请在下面查看我的答案。
    • 很抱歉,如果没有完整的、可重复的示例,很难判断。如果您可以在某处上传您的项目,请在此处分享,我们都可以看看评论。
    • 如果你有兴趣我已经把代码上传到了github。感谢您的帮助!
    【解决方案2】:

    感谢 Sergio Monteleone,我提出了两种我认为可以接受的解决方案。 我已将这两种方法上传到 github: https://github.com/Zephyrox/QT5DX11

    方法 1 - 有效但速度慢

    • 从 QFRAME 而不是主窗口获取 HWND。
    • 将 DX 渲染转换为纹理
    • 将其转换为 QBitmap 并在 qframe paintEvent 中绘制
    • qframe 必须每帧更新

    方法 2 - 几乎可以工作,速度快但会产生闪烁(Sergio Monteleone 的解决方案)

    • 在 qframe 上渲染 DX,将控件放在 qframe 顶部(不在)

      如果你疯狂地在按钮之间移动鼠标,当垂直同步打开时,它们之间会出现一个闪烁的框。 当 VSync 打开时,这种方法在我的机器上实际上速度较慢。这当然是因为什么都没有被渲染。我没有尝试在这里进行任何繁重的渲染,但我怀疑如果 fps 下降到 60 左右,即使没有 vsync,闪烁也会可见。

    编辑。将要渲染的 qframe 上的 UpdatesEnabled 设置为 false,即使 fps 或 vsync 较慢,也不会出现闪烁。

    如果您有兴趣查看实现,请查看 repo。将 DX 纹理转换为 QImage 非常简单:

        HRESULT hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast< void** >(&pSurface));
    
        if(hr != S_OK)
            return;
    
        context->CopyResource(renderTargetTex, pSurface);
    
        D3D11_MAP eMapType = D3D11_MAP_READ;
        D3D11_MAPPED_SUBRESOURCE mappedResource;
        context->Map(renderTargetTex, 0, eMapType, NULL, &mappedResource);
    
        BYTE* pYourBytes = (BYTE*)mappedResource.pData;
    
        bitmap = QImage(pYourBytes, windowWidth, windowHeight, QImage::Format_RGBA8888);
    
            context->Unmap(renderTargetTex, 0);
    

    此代码仅用于测试方法,它缺少大多数错误检查并且可能泄漏大量内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-07
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      相关资源
      最近更新 更多