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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/148275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:36:19  来源:igfitidea点击:

How do I draw transparent DirectX content in a transparent window?

提问by Garth

I want to draw DirectX content so that it appears to be floating over top of the desktop and any other applications that are running. I also need to be able to make the directx content semi-transparent, so other things show through. Is there a way of doing this?

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

I am using Managed DX with C#.

我在 C# 中使用 Managed DX。

采纳答案by Garth

I found a solution which works on Vista, starting from the link provided by OregonGhost. This is the basic process, in C# syntax. This code is in a class inheriting from Form. It doesn't seem to work if in a UserControl:

我找到了一个适用于 Vista 的解决方案,从 OregonGhost 提供的链接开始。这是基本过程,采用 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();
}

Lastly, a Form with default setting will have a glassy looking partially transparent background. Set the FormBorderStyle to "none" and it will be 100% transparent with only your content floating above everything.

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

回答by OregonGhost

I guess that will be hard without using the Desktop Window Manager, i.e. if you want to support Windows XP. With the DWM, it seems to be rather easythough.

我想如果不使用桌面窗口管理器,即如果您想支持 Windows XP,那将很难。使用 DWM,这似乎相当容易

If speed is not an issue, you may get away with rendering to a surface and then copying the rendered image to a layered window. Don't expect that to be fast though.

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

回答by OJ.

WPFis also another option.

WPF也是另一种选择。

Developed by Microsoft, the Windows Presentation Foundation (or WPF) is a computer-software graphical subsystem for rendering user interfaces in Windows-based applications.

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

回答by thewhiteambit

You can either use DirectComposition, LayeredWindows, DesktopWindowManager or WPF. All methods come with their advantages and disadvantages:

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

-DirectComposition is the most efficient one, but needs Windows 8 and is limited to 60Hz.

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

-LayeredWindows are tricky to get working with D3D via Direct2D-interop using DXGI.

-LayeredWindows 使用 DXGI 通过 Direct2D-interop 处理 D3D 很棘手。

-WPF is relatively easy to use via D3DImage, but is also limited to 60Hz and DX9 and no MSAA. Interops to higher DX-Versions via DXGI are possible, also MSAA can be used when the MSAA-Rendertarget is resolved to the native nonMSAA surface.

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

-DesktopWindowManager is great for high performance available since Windows Vista, but DirectX-Versions seem to be limited by the Version the DWM uses (still DX9 on Vista). Workarounds for higher DX-Versions should be possible via DXGI where available.

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

If you don't need per pixel aplha, you can also use the opacity-value of a semi-transparent form.

如果您不需要每像素 aplha,您还可以使用半透明形式的不透明度值。

Or you use the native Win32 method for the Window global alpha (Remember a alpha of 0 will not catch the mouse input):

或者您使用本地 Win32 方法进行 Window 全局 alpha(记住 alpha 为 0 不会捕获鼠标输入):

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

I have been able to use all of the described techniques with C# and SharpDX, but in case of DirectComposition, LayeredWindows and native Win32 a little C++-Wrappercode was needed. For starters I would suggest to go via WPF.

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