如何使用SharpDX绘制透明表面?

2024-02-20

(这个问题是基于进一步调查this https://stackoverflow.com/questions/28960993/hud-basics-using-sharpdx-how-to-draw-over-the-screen-surface其他问题,但不是同一个问题,这是关于绘画问题的非常具体的问题。 )

我正在尝试绘制一个重叠在目标窗口上的透明表面,问题是我不知道如何将其绘制为透明,所以此时我的表面是黑色的,并且我看不到清除黑色的正确方法下面代码中该表面的颜色。

我读过有关像素格式和 alphamodes 的内容,但是,似乎我无法使用AlphaMode.Straight据说这是为了允许透明度。

我知道有一个免费软件应用程序可以做到这一点,它的名字是TurboHUD http://turbohud.freeforums.net/board/4/releases(在游戏客户端的窗口上绘制透明表面来绘制对象的应用程序,即HUD)。老实说,也许很荒谬:我在两年多前就试图实现这一目标,但我仍然不知道如何通过开始在透明表面上绘制对象所需的透明度来开始实现这一目标。

我做错了什么?该示例代码是用 VB.NET 编写的,但我也接受 C# 中的解决方案。

Imports SharpDX
Imports SharpDX.Direct2D1
Imports SharpDX.Direct3D
Imports SharpDX.DXGI
Imports SharpDX.Mathematics.Interop
Imports SharpDX.Windows

Public NotInheritable Class Form1 : Inherits Form

    Private factory As New Direct2D1.Factory(Direct2D1.FactoryType.SingleThreaded)
    Private render As WindowRenderTarget
    Private renderProps As HwndRenderTargetProperties
    Private renderThread As Thread = Nothing

    Private Sub Form1_Load() Handles MyBase.Shown

        Dim hwnd As IntPtr = Process.GetProcessesByName("notepad").Single().MainWindowHandle

        Me.renderProps = New HwndRenderTargetProperties()
        Me.renderProps.Hwnd = hwnd
        Me.renderProps.PixelSize = New Size2(1920, 1080)
        Me.renderProps.PresentOptions = PresentOptions.None

        Me.render = New WindowRenderTarget(Me.factory, New RenderTargetProperties(New PixelFormat(Format.B8G8R8A8_UNorm, Direct2D1.AlphaMode.Premultiplied)), Me.renderProps)

        Me.renderThread = New Thread(New ParameterizedThreadStart(AddressOf Me.DoRender))
        Me.renderThread.Priority = ThreadPriority.Normal
        Me.renderThread.IsBackground = True
        Me.renderThread.Start()

    End Sub

    Private Sub DoRender(ByVal sender As Object)

        While True
            Me.render.BeginDraw()
            ' Me.render.Clear(New RawColor4(0, 0, 0, 0))
            Me.render.Clear(SharpDX.Color.Transparent)
            Me.render.Flush()
            Me.render.EndDraw()
        End While

    End Sub

End Class

上面的代码是 VB.NET 接受答案的改编this https://stackoverflow.com/questions/9863665/sharpdx-directwrite-and-windows-forms问题。


非常感谢@γηράσκω δ' αεί πολλά διδασκόμε我最终实现的建议是使用SharpDx.

下面的代码包含一些对外部库的调用,但是我认为这个想法会非常清晰。

As @γηράσκω δ' αεί πολλά διδασκόμε说,要使用WindowRenderTarget看来我需要以我自己的形式使用它,并且我的形式必须满足这些条件:

  • 背景颜色为黑色。
  • 成为无边界表格。
  • 成为最顶层的窗口(显而易见)。
  • 窗口框架必须扩展到客户区,通过调用DwmExtendFrameIntoClientArea https://msdn.microsoft.com/en-us/library/windows/desktop/aa969512%28v=vs.85%29.aspx功能。

然后我可以调用该方法WindowRenderTarget.Clear(Color.Transparent)使表格透明。请注意,Clear()在上述条件下,该方法不适用于我们自己的窗体之外的任何其他窗口,这意味着如果我们尝试直接在目标窗口上绘制透明表面而不是使用我们的窗体来执行此操作,我们将生成纯色表面不能透明(我真的不明白为什么不能。)

因此,在完成提到的所有基本步骤之后,现在只需进行一些润色工作,例如将源窗口重叠在目标窗口顶部(以产生 HUD 效果),处理目标窗口大小调整,以及你想要什么。下面的代码只是示范性的,我目前还不能很好地处理这些事情。

这是代码:

Imports D2D1 = SharpDX.Direct2D1
Imports D3D = SharpDX.Direct3D
Imports DXGI = SharpDX.DXGI

Imports DxColor = SharpDX.Color
Imports DxPoint = SharpDX.Point
Imports DxRectangle = SharpDX.Rectangle
Imports DxSize = SharpDX.Size2

Imports Device = SharpDX.Direct3D11.Device
Imports MapFlags = SharpDX.Direct3D11.MapFlags

Imports Elektro.Imaging.Tools
Imports Elektro.Interop.Win32
Imports Elektro.Interop.Win32.Enums
Imports Elektro.Interop.Win32.Types

Public NotInheritable Class Form1 : Inherits Form

    <DllImport("dwmapi.dll")>
    Private Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef margins As Margins) As Integer
    End Function

    Private factory As New D2D1.Factory(D2D1.FactoryType.SingleThreaded)
    Private render As D2D1.WindowRenderTarget
    Private renderProps As D2D1.HwndRenderTargetProperties
    Private renderThread As Thread = Nothing

    Private srcHwnd As IntPtr
    Private dstHwnd As IntPtr

    Private Sub Form1_Load() Handles MyBase.Shown

        ' Window handles of source and target window.
        Me.srcHwnd = Me.Handle
        Me.dstHwnd = Process.GetProcessesByName("notepad").Single().MainWindowHandle

        ' Form settings.
        Me.BackColor = Color.Black
        Me.FormBorderStyle = FormBorderStyle.None
        Me.TopMost = True

        ' DWM stuff for later to be able make transparent the source window.
        Dim rc As NativeRectangle ' a win32 RECT
        NativeMethods.GetClientRect(srcHwnd, rc)
        Dim margins As Margins
        margins.TopHeight = rc.Width
        margins.BottomHeight = rc.Height
        DwmExtendFrameIntoClientArea(srcHwnd, margins)
        ' ------------------------------------------------

        Me.renderProps = New D2D1.HwndRenderTargetProperties()
        Me.renderProps.Hwnd = srcHwnd
        Me.renderProps.PixelSize = New DxSize(rc.Width, rc.Height)
        Me.renderProps.PresentOptions = D2D1.PresentOptions.None

        Me.render = New D2D1.WindowRenderTarget(Me.factory, New D2D1.RenderTargetProperties(New D2D1.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D1.AlphaMode.Premultiplied)), Me.renderProps)

        Me.renderThread = New Thread(New ParameterizedThreadStart(AddressOf Me.DoRender))
        Me.renderThread.Priority = ThreadPriority.Normal
        Me.renderThread.IsBackground = True
        Me.renderThread.Start()

    End Sub

    Private Sub DoRender(ByVal sender As Object)

        While True
            Me.OverlapToWindow(Me.srcHwnd, Me.dstHwnd)
            Me.render.BeginDraw()
            Me.render.Clear(DxColor.Transparent)
            Me.render.Flush()
            Me.render.EndDraw()
        End While

    End Sub

    Private Sub OverlapToWindow(ByVal srcHwnd As IntPtr, ByVal dstHwnd As IntPtr)
        ' Gets the (non-client) Rectangle of the windows, taking into account a borderless window of Windows 10.
        Dim srcRect As Rectangle = ImageUtil.GetRealWindowRect(srcHwnd)
        Dim dstRect As Rectangle = ImageUtil.GetRealWindowRect(dstHwnd)

        NativeMethods.SetWindowPos(srcHwnd, dstHwnd,
                                   dstRect.X, dstRect.Y, dstRect.Top, dstRect.Left,
                                   SetWindowPosFlags.IgnoreZOrder Or SetWindowPosFlags.IgnoreResize)
    End Sub

End Class
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用SharpDX绘制透明表面? 的相关文章

随机推荐