如何在透明窗口中绘制透明 DirectX 内容?

Posted

技术标签:

【中文标题】如何在透明窗口中绘制透明 DirectX 内容?【英文标题】:How do I draw transparent DirectX content in a transparent window? 【发布时间】:2010-09-13 23:30:10 【问题描述】:

我想绘制 DirectX 内容,使其看起来漂浮在桌面和任何其他正在运行的应用程序之上。我还需要能够使 directx 内容半透明,以便其他内容显示出来。有没有办法做到这一点?

我正在使用带有 C# 的托管 DX。

【问题讨论】:

分层窗口不是一个选项吗? msdn.microsoft.com/en-us/library/ms997507.aspx 【参考方案1】:

从 OregonGhost 提供的链接开始,我找到了适用于 Vista 的解决方案。这是 C# 语法中的基本过程。此代码位于从 Form 继承的类中。如果在 UserControl 中,它似乎不起作用:

//this will allow you to import the necessary functions from the .dll
using System.Runtime.InteropServices;

//this imports the function used to extend the transparent window border.
[DllImport("dwmapi.dll")]
static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMargins);

//this is used to specify the boundaries of the transparent area
internal struct Margins 
    public int Left, Right, Top, Bottom;

private Margins marg;

//Do this every time the form is resized. It causes the window to be made transparent.
marg.Left = 0;
marg.Top = 0;
marg.Right = this.Width;
marg.Bottom = this.Height;
DwmExtendFrameIntoClientArea(this.Handle, ref marg);

//This initializes the DirectX device. It needs to be done once.
//The alpha channel in the backbuffer is critical.
PresentParameters presentParameters = new PresentParameters();
presentParameters.Windowed = true;
presentParameters.SwapEffect = SwapEffect.Discard;
presentParameters.BackBufferFormat = Format.A8R8G8B8;

Device device = new Device(0, DeviceType.Hardware, this.Handle,
CreateFlags.HardwareVertexProcessing, presentParameters);

//the OnPaint functions maked the background transparent by drawing black on it.
//For whatever reason this results in transparency.
protected override void OnPaint(PaintEventArgs e) 
    Graphics g = e.Graphics;

    // black brush for Alpha transparency
    SolidBrush blackBrush = new SolidBrush(Color.Black);
    g.FillRectangle(blackBrush, 0, 0, Width, Height);
    blackBrush.Dispose();

    //call your DirectX rendering function here


//this is the dx rendering function. The Argb clearing function is important,
//as it makes the directx background transparent.
protected void dxrendering() 
    device.Clear(ClearFlags.Target, Color.FromArgb(0, 0, 0, 0), 1.0f, 0);

    device.BeginScene();
    //draw stuff here.
    device.EndScene();
    device.Present();

最后,具有默认设置的表单将具有玻璃状的部分透明背景。将 FormBorderStyle 设置为“none”,它将 100% 透明,只有您的内容漂浮在所有内容之上。

【讨论】:

【参考方案2】:

您可以使用 DirectComposition、LayeredWindows、DesktopWindowManager 或 WPF。所有方法都有其优点和缺点:

-DirectComposition 是最有效的一种,但需要 Windows 8 并且限制为 60Hz。

-LayeredWindows 很难通过 Direct2D-interop 使用 DXGI 来处理 D3D。

-WPF 通过 D3DImage 相对容易使用,但也仅限于 60Hz 和 DX9 且没有 MSAA。可以通过 DXGI 与更高的 DX 版本互操作,当 MSAA-Rendertarget 解析为原生非 MSAA 表面时,也可以使用 MSAA。

-DesktopWindowManager 非常适合自 Windows Vista 以来提供的高性能,但 DirectX 版本似乎受到 DWM 使用的版本的限制(在 Vista 上仍然是 DX9)。更高 DX 版本的解决方法应该可以通过 DXGI(如果可用)来实现。

如果不需要每像素 aplha,也可以使用半透明形式的 opacity-value。

或者您使用本机 Win32 方法获取 Window 全局 alpha(请记住 0 的 alpha 不会捕获鼠标输入):

SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
COLORREF color = 0;
BYTE alpha = 128;
SetLayeredWindowAttributes(hWnd, color, alpha, LWA_ALPHA);

我已经能够在 C# 和 SharpDX 中使用所有描述的技术,但在 DirectComposition、LayeredWindows 和本机 Win32 的情况下,需要一点 C++-Wrappercode。对于初学者,我建议通过 WPF。

【讨论】:

【参考方案3】:

我想如果不使用桌面窗口管理器会很难,也就是说,如果你想支持 Windows XP。使用 DWM,它似乎是 rather easy。

如果速度不是问题,您可以先渲染到表面,然后将渲染的图像复制到分层窗口。不过不要指望这会很快。

【讨论】:

只有 dx9 才有用,因为 Vista 中的 DWM 是 dx9。 Windows 7 将使用 dx10,这样会很好。【参考方案4】:

WPF 也是另一种选择。

由 Microsoft 开发的 Windows Presentation Foundation(或 WPF)是一个计算机软件图形子系统,用于在基于 Windows 的应用程序中呈现用户界面。

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。 请注意这个问题在近 4 年前的 beta 测试期间是如何回答的?那时的问答都是实验性的。这当然不是一个绝妙的答案,但它一个答案,也是一个可行的答案。链接和内容一样有效。

以上是关于如何在透明窗口中绘制透明 DirectX 内容?的主要内容,如果未能解决你的问题,请参考以下文章

DirectX11 With Windows SDK--29 计算着色器:内存模型线程同步;实现顺序无关透明度(OIT)

android中,如何用canvas绘制透明?

如何将CMD窗口背景改成透明?

在半透明框架/面板/组件上重新绘制。

如何给 GtkEventBox 一个透明背景?

QT软件开发: 点击鼠标在窗口里绘制矩形(窗口透明背景)