Извините за код, приведенный ниже, я полностью освоился с 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 - был бы очень признателен за руководство ..