如何使用SharpDX绘制透明表面? [英] How to draw a transparent surface using SharpDX?

查看:211
本文介绍了如何使用SharpDX绘制透明表面?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(此问题基于对 这个问题 ,但不是同一问题,这是有关绘画问题的非常具体的问题。)

( This question is based on further investigations of this other question, but isn't the same question, this is very specific question about painting issues. )

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

I'm trying to draw a transparent surface overlapped on a target window, the problem is that I don't know how to paint it transparent, so by the moment my surface is black, and I cannot see the proper way to clear the black color of that surface in the code below.

我曾经读过有关pixelformats和alphamodes的信息,但是,似乎我不能使用 AlphaMode.Straight 应该是为了允许透明。

I'd read about pixelformats and alphamodes, however, seems I cannot use the AlphaMode.Straight which supposedly is for allow transparency.

我知道一个可以做到这一点的免费软件,其名称为 TurboHUD (在透明表面在游戏客户端的窗口中绘制对象(即HUD)。老实说,也许是荒谬的:我试图从两年多以前就做到这一点,但我仍然不知道如何通过执行透明操作来开始执行此操作,我需要在透明表面上绘制对象。

I'm aware of a freeware application that can do this, its name is TurboHUD (an application that draws a transparent surface on the window of a game client to draw objects, that is, a HUD). To be honest and maybe ridiculous: I'm trying to acchieve this from more than two years ago, I still don't know how to start doing this by doing the transparency I need to start drawing objects on a transparent surface.

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

What I'm doing wrong?. This sample code is written in VB.NET, but I accept too a solution in 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改编的 这个问题

The code above is a VB.NET adaption of the accepted answer of this question.

推荐答案

非常感谢@ γηράσκωδ'αείπολλάδιδασκόμε的建议我终于使用 SharpDx 做到了这一点。

Thanks a lot to @γηράσκω δ' αεί πολλά διδασκόμε suggestions I finally acchieved to do this using SharpDx.

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

The code below contains some calls to a external library, however I think the idea will be very clear.

由于@ γηράσκωδ'αεί πολλάδιδασκόμε说,要使用 WindowRenderTarget 似乎我需要以自己的形式使用,并且我的形式必须满足以下条件:

As @γηράσκω δ' αεί πολλά διδασκόμε said, to use the WindowRenderTarget seems that I need to use it in my own form, and my form must satisfy these conditions:


  • 具有黑色背景颜色。

  • 成为无边界表单。

  • 是最上面的窗口(显而易见)。

  • 必须通过调用 DwmExtendFrameIntoClientArea 函数。

  • Have a black background color.
  • Be a borderless Form.
  • Be the top-most window (obvious).
  • The window frame must be extended into the client area, by calling DwmExtendFrameIntoClientArea function.

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

Then I can call the method WindowRenderTarget.Clear(Color.Transparent) to make the Form transparent. Note that the Clear() method will not work for any other window than our own Form with the conditions mentioned above, this means that if we try to paint a transparent surface directlly on the target window instead of using our form to do that, we will produce a solid-color surface that can't be transparent (I really don't understand why can't.)

因此,在完成所有提到的基本步骤之后,现在只需打磨一下事情,例如源窗口在目标窗口顶部的重叠(以产生HUD效果),处理目标即可。调整窗口大小以及您的期望。下面的代码只是示例性的,目前我还不能很好地处理这些事情。

So after all the basic steps mentioned are done, now will be just a matter of polish things like the overlapping of the source-window on the top of the target-window (to produce the HUD effect), handle the target window resizing, and what you wish. The code below is just demonstrative, I don't handle very good those things by the moment.

这里是代码:

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

这篇关于如何使用SharpDX绘制透明表面?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆