Testo in Direct3D12 4195 Visite) DirectX 12
Le Direct3D12, come avete potuto notare, sono state ridotte all’essenziale per dare la massima flessibilità allo sviluppatore. Molte utility, tuttavia, non esistono più, dal caricamento delle texture alla scrittura del testo.
Quest’ultima, in particolare, richiede di implementare un proprio sistema. In attesa di creare i propri metodi per scrivere il testo nelle schermate del vostro gioco, si può utilizzare un altro componente che invece è stato pensato proprio per questo: Direct2D.
Questa libreria replica le GDI (le librerie grafiche di Windows per disegnare e scrivere a video) ottimizzandole per la scheda video.
Nei tutorial per Direct3D11 ho descritto come far lavorare insieme Direct3D con Direct2D, in Direct3D12 c’è da fare uno step in più (ricordiamo che Direct3D12 sono fortemente parallelizzate).
Per prima cosa dobbiamo creare un Device per Direct3D11 a partire da Direct3D12
SharpDX.Direct3D11.Device device11 = SharpDX.Direct3D11.Device.CreateFromDirect3D12(device, SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport, null, null, commandQueue);
SharpDX.Direct3D11.DeviceContext deviceContext11 = device11.ImmediateContext;
SharpDX.Direct3D11.ID3D11On12Device device11on12 = device11.QueryInterface<SharpDX.Direct3D11.ID3D11On12Device>();
Come potete vedere ci sono metodi apposite per creare un Device (con il relative DeviceContext) a partire da un Device12
L’ultimo oggetto è il più interessante: ID3D11on12Device. Questo oggetto serve a fare da ponte tra i due Device per poter usare Direct3D11 su Direct3D12 (utile se avete funzioni per le vecchie librerie).
Ora inizializziamo gli oggetti per Direct2D. Dato che Direct3D12 utilizza sempre più di un BackBuffer alla volta, dovremo creare altrettanti oggetti RenderTarget per Direct2D.
SharpDX.Direct3D11.Resource[] wrappedBackBuffers = new SharpDX.Direct3D11.Resource[FrameCount];
SharpDX.Direct2D1.RenderTarget[] direct2DRenderTarget = new SharpDX.Direct2D1.RenderTarget[FrameCount];
var d2dFactory = new SharpDX.Direct2D1.Factory(SharpDX.Direct2D1.FactoryType.MultiThreaded);
for (int n = 0; n < FrameCount; n++)
{
SharpDX.Direct3D11.D3D11ResourceFlags format = new SharpDX.Direct3D11.D3D11ResourceFlags()
{
BindFlags = (int)SharpDX.Direct3D11.BindFlags.RenderTarget,
CPUAccessFlags = (int)SharpDX.Direct3D11.CpuAccessFlags.None
};
device11on12.CreateWrappedResource( renderTargets[n], format, (int)ResourceStates.Present, (int)ResourceStates.RenderTarget, typeof(SharpDX.Direct3D11.Resource).GUID, out wrappedBackBuffers[n]);
var d2dSurface = wrappedBackBuffers[n].QueryInterface<Surface>();
direct2DRenderTarget[n] = new SharpDX.Direct2D1.RenderTarget(d2dFactory, d2dSurface, new SharpDX.Direct2D1.RenderTargetProperties(new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied)));
d2dSurface.Dispose();
}
d2dFactory.Dispose();
A partire dai render target create per Direct3D12, andremo a prendere le WrappedResource (in pratica il puntamento alle superfici D3D12 per 11) e creeremo I render target per Direct2D.
Ora potremo andare ad utilizzare le Direct2D:
Creiamo ad esempio un font ed un brush
var directWriteFactory = new SharpDX.DirectWrite.Factory();
SharpDX.DirectWrite.TextFormat textFormat = new SharpDX.DirectWrite.TextFormat(directWriteFactory, "Arial", SharpDX.DirectWrite.FontWeight.Bold, SharpDX.DirectWrite.FontStyle.Normal, 48) { TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading, ParagraphAlignment = SharpDX.DirectWrite.ParagraphAlignment.Near };
SharpDX.Direct2D1.SolidColorBrush textBrush = new SharpDX.Direct2D1.SolidColorBrush(direct2DRenderTarget[0], Color.White);
directWriteFactory.Dispose();
Nel ciclo di rendering ora potremo utilizzare i nostri oggetti per scrivere. Prima del present (ma fuori dalla registrazione della CommandList).
Per prima cosa si acquisisce il backbuffer
device11on12.AcquireWrappedResources(new SharpDX.Direct3D11.Resource[] { wrappedBackBuffers[frameIndex] }, 1);
Quindi si utilizza Direct2D nel modo consueto utilizzando il render target corrispondente al backbuffer che stiamo utilizzando in Direct3D12.
direct2DRenderTarget[frameIndex].BeginDraw();
direct2DRenderTarget[frameIndex].DrawText("Hello Text", textFormat, new SharpDX.Mathematics.Interop.RawRectangleF(10, 10, 2000, 500), textBrush);
direct2DRenderTarget[frameIndex].EndDraw();
Infine si rilascia il backbuffer e si esegue il comando flush sul deviceContext.
device11on12.ReleaseWrappedResources(new SharpDX.Direct3D11.Resource[] { wrappedBackBuffers[frameIndex] }, 1);
deviceContext11.Flush();
Ora sullo schermo sarà visibile il testo che avete scritto. Direct2D è una libreria molto potente, potrete facilmente creare testi e grafica bidimensionale tuttavia attenzione:
Direct3D12 è pensata per parallelizzare il processo di rendering limitando al massimo lo scambio tra CPU e GPU. Direct2D utilizza la logica di DirectX11 e potrebbe ridurre le prestazioni delle vostre applicazioni.
Vi lascio alla demo sul mio repository Github