2016-06-23 27 views
10

(Questa domanda si basa su ulteriori indagini this altra domanda, ma non è la stessa domanda, questa è la domanda molto specifica sui problemi di verniciatura.)Come disegnare una superficie trasparente usando SharpDX?

sto cercando di disegnare una superficie trasparente sovrapposto su una finestra di destinazione, il problema è che non so come dipingerlo trasparente, quindi nel momento in cui la mia superficie è nera, e non riesco a vedere il modo corretto per cancellare il colore nero di quella superficie nel codice qui sotto.

Ho letto di pixelformats e alphamodes, tuttavia, sembra che non sia possibile utilizzare lo AlphaMode.Straight che presumibilmente è per consentire la trasparenza.

Sono consapevole di un'applicazione freeware che può fare questo, il suo nome è TurboHUD (un'applicazione che disegna una superficie trasparente sulla finestra di un client di gioco per disegnare oggetti, cioè, un HUD). Per essere onesto e forse ridicolo: sto cercando di ottenere questo risultato da più di due anni fa, non so ancora come iniziare a fare questo facendo la trasparenza di cui ho bisogno per iniziare a disegnare oggetti su una superficie trasparente.

Cosa sto facendo male ?. Questo codice di esempio è scritto in VB.NET, ma accetto anche una soluzione 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 

Il codice di cui sopra è un adattamento VB.NET della risposta accettata di this domanda.

+0

Ecco un link vale la pena guardare - http://stackoverflow.com/questions/26646715/how-can-i-draw-a-transparent-3d-object- with-the-sharpdx-toolkit – AGrammerPro

+0

Grazie per il commento e per aver cercato di aiutare. Ho anche trovato questa domanda, ma penso (penso) che non sia applicabile a questo scenario, perché è per rendere trasparente una forma/oggetto, non una superficie. Onestamente non so come testare/riprodurre quell'esempio. – ElektroStudios

+1

Guardando [questa pagina MSDN] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd756766 (v = vs.85) .aspx # supported_formats_for__id2d1hwndrendertarget) sembra che l'alfa 'Straight' la modalità non è supportata quando si ha a che fare con l'interfaccia 'ID2D1HwndRenderTarget' (che suppongo che SharpDX stia usando). –

risposta

2

Grazie mille a @γηράσκω δ' αεί πολλά διδασκόμε suggerimenti che finalmente acchieved di farlo usando SharpDx.

Il codice seguente contiene alcune chiamate a una libreria esterna, tuttavia penso che l'idea sarà molto chiara.

Come @γηράσκω δ' αεί πολλά διδασκόμε detto, di utilizzare il WindowRenderTarget sembra che ho bisogno di usarlo nella mia propria forma, e la mia forma devono soddisfare queste condizioni:

  • hanno uno sfondo nero colore.
  • Essere una forma senza bordi.
  • Essere la finestra più in alto (ovvio).
  • Il frame della finestra deve essere esteso nell'area client, chiamando la funzione DwmExtendFrameIntoClientArea.

Quindi posso chiamare il metodo WindowRenderTarget.Clear(Color.Transparent) per rendere trasparente il modulo. Notare che il metodo Clear() non funzionerà per nessun'altra finestra rispetto al proprio Form con le condizioni menzionate sopra, questo significa che se proviamo a dipingere una superficie trasparente direttamente sulla finestra di destinazione invece di usare il nostro modulo per farlo, produrremo una superficie a tinta unita che non può essere trasparente (non capisco davvero perché non sia possibile).

Quindi, dopo che tutti i passaggi di base menzionati sono stati fatti, ora sarà solo una questione di cose lucidate come la sovrapposizione della finestra sorgente nella parte superiore della finestra di destinazione (per produrre l'effetto HUD), gestire il ridimensionamento della finestra di destinazione e ciò che desideri. Il codice sotto è solo dimostrativo, non gestisco molto bene quelle cose al momento.

Ecco il codice:

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 
Problemi correlati