2016-06-23 10 views
10

(Diese Frage auf weitere Untersuchungen von this andere Frage basiert, ist aber nicht die gleiche Frage, ist diese sehr spezifische Frage über die Malerei Fragen.)Wie zeichne ich eine transparente Oberfläche mit SharpDX?

Ich versuche, eine transparente Oberfläche auf überlappt zu ziehen ein Zielfenster, das Problem ist, dass ich nicht weiß, wie man es transparent malt, also bis zu dem Moment, wo meine Oberfläche schwarz ist, und ich kann nicht den richtigen Weg sehen, die schwarze Farbe dieser Oberfläche im Code unten zu löschen.

Ich habe über Pixelformats und Alphamodes gelesen, scheint jedoch, dass ich die AlphaMode.Straight nicht verwenden kann, die angeblich für Transparenz ist.

Ich bin mir dessen bewusst ein Freeware-Anwendung, die dies tun kann, ist sein Name TurboHUD (eine Anwendung, die auf dem Fenster eines Spiel-Client eine transparente Oberfläche zieht Objekte zu zeichnen, das heißt, ein HUD). Um ehrlich zu sein und vielleicht lächerlich: Ich versuche, dies vor mehr als zwei Jahren zu erreichen, ich weiß immer noch nicht, wie ich damit anfangen soll, indem ich die Transparenz mache, die ich brauche, um Objekte auf einer transparenten Oberfläche zu zeichnen.

Was mache ich falsch ?. Dieser Beispielcode ist in VB.NET geschrieben, aber ich akzeptiere auch eine Lösung 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 

Der obige Code ist eine VB.NET Anpassung der akzeptierten Antwort von this Frage.

+0

Hier ist ein Link einen Blick wert - http://stackoverflow.com/questions/26646715/how-can-i-draw-a-transparent-3d-object- with-the-sharpdx-toolkit – AGrammerPro

+0

Danke für den Kommentar und für den Versuch zu helfen. Ich habe auch diese Frage gefunden, aber ich denke (denke ich), dass das nicht auf dieses Szenario anwendbar ist, weil das eine Form/ein Objekt transparent macht, keine Oberfläche. Ehrlich gesagt weiß ich nicht, wie man dieses Beispiel testet/reproduziert. – ElektroStudios

+1

Mit Blick auf [diese MSDN-Seite] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd756766 (v = vs.85) .aspx # supported_formats_for_id2d1hwndrendertarget) scheint es, dass die 'Straight' alpha Modus wird nicht unterstützt, wenn es um die 'ID2D1HwndRenderTarget'-Schnittstelle geht (was ich denke SharpDX verwendet). –

Antwort

2

Vielen Dank an @γηράσκω δ‘αεί πολλά διδασκόμε Vorschläge, die ich dies mit SharpDx schließlich acchieved zu tun.

Der folgende Code enthält einige Aufrufe an eine externe Bibliothek, aber ich denke, die Idee wird sehr klar sein.

Wie @γηράσκω δ‘αεί πολλά διδασκόμε sagte, zu verwenden die WindowRenderTarget scheint, dass ich es in meiner eigenen Form verwenden müssen, und meine Form diese Bedingungen erfüllen müssen:

  • haben einen schwarzen Hintergrund Farbe.
  • Sei eine grenzenlose Form.
  • Seien Sie das oberste Fenster (offensichtlich).
  • Der Fensterrahmen muss in den Client-Bereich erweitert werden, indem DwmExtendFrameIntoClientArea Funktion aufgerufen wird.

Dann kann ich die Methode WindowRenderTarget.Clear(Color.Transparent) aufrufen, um das Formular transparent zu machen. Beachten Sie, dass die Clear() Methode für kein anderes Fenster als unser eigenes Formular mit den oben genannten Bedingungen funktioniert. Das bedeutet, wenn wir versuchen, eine transparente Oberfläche direkt auf das Zielfenster zu malen, anstatt unser Formular dafür zu verwenden, werden wir produzieren eine einfarbige Oberfläche, die nicht transparent sein kann (ich verstehe wirklich nicht, warum nicht.)

Also, nachdem alle grundlegenden Schritte getan sind, wird jetzt nur eine Frage der polnischen Dinge wie die Überlappung sein des Quellfensters am oberen Rand des Zielfensters (um den HUD-Effekt zu erzeugen), handle mit der Größenänderung des Zielfensters und was du willst. Der Code unten ist nur demonstrativ, ich behandle diese Dinge im Moment nicht sehr gut.Hier

ist der Code:

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 
Verwandte Themen