Использование эффектов изображения SharpDX - PullRequest
0 голосов
/ 07 октября 2018

Извините за код, приведенный ниже, я полностью освоился с DirectX и действительно изо всех сил пытаюсь осмыслить разные части.Я пытаюсь добиться этого через SharpDX.Мне удалось (в другом коде) визуализировать прямоугольники, изображения и текст на экране без особых затруднений.Тем не менее, все они используют RenderTaget для рисования на холсте.Тем не менее, эффекты, кажется, требуют использования RenderContext, что сбивает меня с толку.

Я собрал некоторый код, объединив два примера в репозитории SharpDX.Первый выводит светящийся прямоугольник на экран.Другой (переименованный DrawImageWithEffect в моем коде) возвращает растровое изображение с добавленными эффектами.Последний работает, если используется непосредственно в примере (сохраняет изображение на диск), но я хочу, чтобы он просто возвращал растровое изображение для дальнейшего рендеринга.

Сообщение об ошибке появляется по адресу:

d2dRenderTarget.EndDraw()

и гласит:

SharpDX.SharpDXException
  HResult=0x88990012
  Message=HRESULT: [0x88990012], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_WRONG_FACTORY/WrongFactory], Message: Objects used together must be created from the same factory instance.

  Source=SharpDX
  StackTrace:
   at SharpDX.Result.CheckError()
   at SharpDX.Direct2D1.RenderTarget.EndDraw()
   at Tests_SharpDX4.RenderWindow2._Lambda$__18-0() in C:\Users\Steve\Documents\Visual Studio 2017\Projects\Tests_SharpDX4\Tests_SharpDX4\Classes\TestRender5.vb:line 101
   at Tests_SharpDX4.RenderWindow2._Lambda$__R18-1()
   at SharpDX.Windows.RenderLoop.Run(Control form, RenderCallback renderCallback, Boolean useApplicationDoEvents)
   at Tests_SharpDX4.RenderWindow2.Render() in C:\Users\Steve\Documents\Visual Studio 2017\Projects\Tests_SharpDX4\Tests_SharpDX4\Classes\TestRender5.vb:line 92
   at Tests_SharpDX4.Form1.Button1_Click(Object sender, EventArgs e) in C:\Users\Steve\Documents\Visual Studio 2017\Projects\Tests_SharpDX4\Tests_SharpDX4\Form1.vb:line 8
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
   at Tests_SharpDX4.My.MyApplication.Main(String[] Args) in :line 81

Полный код (будьте осторожны - хакерский и грубый!):

Imports SharpDX
Imports SharpDX.Direct2D1
Imports SharpDX.Direct3D
Imports SharpDX.Direct3D11
Imports SharpDX.DXGI
Imports SharpDX.Windows
Imports SharpDX.Mathematics
Imports SharpDX.IO
Imports D3D11 = SharpDX.Direct3D11
Imports d3d = SharpDX.Direct3D11
Imports D2 = SharpDX.Direct2D1
Imports dxgi = SharpDX.DXGI
Imports wic = SharpDX.WIC
Imports dw = SharpDX.DirectWrite
Imports Factory = SharpDX.DXGI.Factory
Imports AlphaMode = SharpDX.Direct2D1.AlphaMode
Imports Device = SharpDX.Direct3D11.Device


Public Class RenderWindow2
    Implements IDisposable

    'Redner Form
    Dim form As RenderForm = New RenderForm("SharpDX - MiniTri Direct2D - Direct3D 10 Sample")

    'Swapchain description
    Dim desc = New SwapChainDescription() With {
            .BufferCount = 1,
            .ModeDescription = New ModeDescription(form.ClientSize.Width, form.ClientSize.Height, New Rational(60, 1), Format.R8G8B8A8_UNorm),
            .IsWindowed = True,
            .OutputHandle = form.Handle,
            .SampleDescription = New SampleDescription(1, 0),
            .SwapEffect = SwapEffect.Discard,
            .Usage = Usage.RenderTargetOutput
        }

    Dim device As Device
    Dim swapChain As SwapChain

    Dim d2dFactory = New SharpDX.Direct2D1.Factory()

    Dim backBuffer As Texture2D
    Dim renderView As RenderTargetView
    Dim factory As Factory

    Dim surface As Surface

    Dim d2dRenderTarget As RenderTarget

    Dim stopwatch As Stopwatch = New Stopwatch()
    Dim solidColorBrush As SolidColorBrush

    Dim width As Integer = form.ClientSize.Width
    Dim height As Integer = form.ClientSize.Height
    Dim rectangleGeometry = New RoundedRectangleGeometry(d2dFactory, New RoundedRectangle() With {
            .RadiusX = 32,
            .RadiusY = 32,
            .Rect = New SharpDX.RectangleF(128, 128, width - 128 * 2, height - 128 * 2)
        })

    Dim bm As Bitmap1


    Public Sub New()

        Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, New SharpDX.Direct3D.FeatureLevel() {SharpDX.Direct3D.FeatureLevel.Level_10_0}, desc, device, swapChain)

        factory = swapChain.GetParent(Of Factory)()
        factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll)
        backBuffer = Texture2D.FromSwapChain(Of Texture2D)(swapChain, 0)
        renderView = New RenderTargetView(device, backBuffer)

        surface = backBuffer.QueryInterface(Of Surface)()
        d2dRenderTarget = New RenderTarget(d2dFactory, surface, New RenderTargetProperties(New PixelFormat(Format.Unknown, AlphaMode.Premultiplied)))

        solidColorBrush = New SolidColorBrush(d2dRenderTarget, Color.White)

        stopwatch.Start()

        LoadResources()

    End Sub

    Private Sub LoadResources()

        bm = DrawImageWithEffect("arcademachine.png")

    End Sub

    Public Sub Render()

        RenderLoop.Run(form, Function()
                                 d2dRenderTarget.BeginDraw()

                                 d2dRenderTarget.Clear(Color.DarkBlue)
                                 solidColorBrush.Color = New Color4(1, 1, 1, CSng(Math.Abs(Math.Cos(stopwatch.ElapsedMilliseconds * 0.001))))
                                 d2dRenderTarget.FillGeometry(rectangleGeometry, solidColorBrush, Nothing)

                                 d2dRenderTarget.DrawBitmap(bm, 1, BitmapInterpolationMode.Linear)

                                 d2dRenderTarget.EndDraw()
                                 swapChain.Present(0, PresentFlags.None)
                             End Function)
    End Sub

    Public Function DrawImageWithEffect(inputPath As String) As Bitmap1

        ' This sample represents a method of offline image processing.
        ' It requires references to DirectX 11.1, so it will run only on Windows 7 Platform Update Or above.
        ' It references SharpDX from Win8Desktop-net40 folder.
        ' The same method Is applicable in Windows 8 modern apps.
        ' This code skips all sanity checks to focus on feature demonstration. In production apps do Not forget to check
        ' for parameters correctness And feature support.

        ' The sample does the following
        ' 1. Initializes references to all needed devices And factories
        ' 2. Loads an input image And stores its size to be used in the output image
        ' 3. Prepares an effect graph to process the image
        ' 4. Prepares some text to draw it over image (useful for any kind of annotations, watermarks, etc).
        ' 5. Initializes the render target - here can be any compatible surface.
        ' 6. Draws the prepared effect graph And text.
        ' 7. Saves the image in the output file.
        ' 8. Disposes everything.
        ' 9. Starts the default associated program to display the result.

        Dim outputPath = "Output.png"
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' INITIALIZATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' initialize the D3D device which will allow to render to image any graphics - 3D Or 2D
        Dim defaultDevice = device
        Dim d3dDevice = defaultDevice.QueryInterface(Of Direct3D11.Device1)()
        Dim dxgiDevice = d3dDevice.QueryInterface(Of dxgi.Device)()
        Dim d2dDevice = New D2.Device(dxgiDevice)

        'Dim imagingFactory = New wic.ImagingFactory2()
        Dim imagingFactory = New wic.ImagingFactory2()


        ' initialize the DeviceContext - it will be the D2D render target and will allow all rendering operations
        Dim d2dContext = New D2.DeviceContext(d2dDevice, D2.DeviceContextOptions.None)
        Dim dwFactory = New dw.Factory()

        ' specify a pixel format that is supported by both D2D and WIC
        Dim d2PixelFormat = New D2.PixelFormat(dxgi.Format.R8G8B8A8_UNorm, D2.AlphaMode.Premultiplied)
        Dim wicPixelFormat = wic.PixelFormat.Format32bppPRGBA

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' IMAGE LOADING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        Dim decoder = New wic.PngBitmapDecoder(imagingFactory)
        Dim inputStream = New wic.WICStream(imagingFactory, inputPath, SharpDX.IO.NativeFileAccess.Read)
        decoder.Initialize(inputStream, wic.DecodeOptions.CacheOnLoad)

        ' decode the loaded image to a format that can be consumed by D2D
        Dim formatConverter = New wic.FormatConverter(imagingFactory)
        formatConverter.Initialize(decoder.GetFrame(0), wicPixelFormat)

        ' load the base image into a D2D Bitmap
        'var inputBitmap = d2.Bitmap1.FromWicBitmap(d2dContext, formatConverter, New d2.BitmapProperties1(d2PixelFormat));

        ' store the image size - output will be of the same size
        Dim inputImageSize = formatConverter.Size
        Dim pixelWidth = inputImageSize.Width
        Dim pixelHeight = inputImageSize.Height

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' EFFECT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' Effect 1  BitmapSource -take decoded image data And get a BitmapSource from it
        Dim bitmapSourceEffect = New D2.Effects.BitmapSource(d2dContext)
        bitmapSourceEffect.WicBitmapSource = formatConverter

        ' Effect 2 : GaussianBlur - give the bitmapsource a gaussian blurred effect
        Dim gaussianBlurEffect = New D2.Effects.GaussianBlur(d2dContext)
        gaussianBlurEffect.SetInput(0, bitmapSourceEffect.Output, True)
        gaussianBlurEffect.StandardDeviation = 5.0F

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' OVERLAY TEXT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Dim textFormat = New dw.TextFormat(dwFactory, "Arial", 15.0F)

        ' draw a long text to show the automatic line wrapping
        Dim textToDraw = "MAGO WOZ ERE"

        ' create the text layout - this improves the drawing performance for static text
        ' as the glyph positions are precalculated
        Dim textLayout = New dw.TextLayout(dwFactory, textToDraw, textFormat, 300.0F, 1000.0F)
        Dim textBrush = New D2.SolidColorBrush(d2dContext, New Interop.RawColor4(0, 0, 0.8, 1))

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' RENDER TARGET SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' create the d2d bitmap description using default flags (from SharpDX samples) And 96 DPI
        Dim d2dBitmapProps = New D2.BitmapProperties1(d2PixelFormat, 96, 96, D2.BitmapOptions.Target Or D2.BitmapOptions.CannotDraw)
        Dim d2dRenderTarget = New D2.Bitmap1(d2dContext, New SharpDX.Size2(pixelWidth, pixelHeight), d2dBitmapProps)

        ' the render target
        d2dContext.Target = d2dRenderTarget

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' DRAWING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' slow preparations - fast drawing
        d2dContext.BeginDraw()
        d2dContext.DrawImage(gaussianBlurEffect)
        d2dContext.DrawTextLayout(New Vector2(5.0F, 5.0F), textLayout, textBrush)
        d2dContext.EndDraw()

        ' MY EDIT:
        Return d2dRenderTarget

        ' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' IMAGE SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' delete the output file if it already exists

        If System.IO.File.Exists(outputPath) Then System.IO.File.Delete(outputPath)

        ' use the appropiate overload to write either to stream or to a file
        Dim stream = New wic.WICStream(imagingFactory, outputPath, NativeFileAccess.Write)
        'Dim st2 = New wic.WICStream(imagingFactory,)
        ' select the image encoding format HERE

        Dim encoder = New wic.PngBitmapEncoder(imagingFactory)
        encoder.Initialize(stream)
        Dim bitmapFrameEncode = New wic.BitmapFrameEncode(encoder)
        bitmapFrameEncode.Initialize()
        bitmapFrameEncode.SetSize(pixelWidth, pixelHeight)
        bitmapFrameEncode.SetPixelFormat(wicPixelFormat)

        ' this is the trick to write D2D1 bitmap to WIC
        Dim imageEncoder = New wic.ImageEncoder(imagingFactory, d2dDevice)
        imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, New wic.ImageParameters(d2PixelFormat, 96, 96, 0, 0, pixelWidth, pixelHeight))
        bitmapFrameEncode.Commit()
        encoder.Commit()

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' CLEANUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' dispose everything And free used resources

        bitmapFrameEncode.Dispose()
        encoder.Dispose()
        stream.Dispose()
        textBrush.Dispose()
        textLayout.Dispose()
        textFormat.Dispose()
        formatConverter.Dispose()
        gaussianBlurEffect.Dispose()
        bitmapSourceEffect.Dispose()
        d2dRenderTarget.Dispose()
        inputStream.Dispose()
        decoder.Dispose()
        d2dContext.Dispose()
        dwFactory.Dispose()
        imagingFactory.Dispose()
        d2dDevice.Dispose()
        dxgiDevice.Dispose()
        d3dDevice.Dispose()
        defaultDevice.Dispose()
        'System.Diagnostics.Process.Start(outputPath)
    End Function


#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
                renderView.Dispose()
                backBuffer.Dispose()
                device.ImmediateContext.ClearState()
                device.ImmediateContext.Flush()
                device.Dispose()
                device.Dispose()
                swapChain.Dispose()
                factory.Dispose()
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
        Dispose(True)
        ' TODO: uncomment the following line if Finalize() is overridden above.
        ' GC.SuppressFinalize(Me)
    End Sub
#End Region
End Class

Я рву свои волосы здесь с DX - был бы очень признателен за руководство ..

...