I started to learn DirectX. I wanted, of course, to use it in a WPF environment. I don’t hope to write a game (yet?) but I thought it would be a good API for high performance data visualization. Or simply capturing and tweaking web cam output.
I discovered SharpDX by Alexandre Mutel, which is a 100% managed wrapper. Better yet, it performs better than all other managed wrapper it seems! At least according to this.
To start with DirectX, you need to download the DirectX SDK which is good because it contains tons of tutorials and samples.
I started by rewriting all the 7 MSDN tutorials in C#. I try to write code very close to the original C++ (for comparison purposes) yet beautified (thanks to C#!), I shall say it came out well!
Speaking of which, when you work with DirectX, you have to write (pixel, vertex, hull, etc.) shaders (introduction). Basically they are little programs that convert the data from one graphic processing stage to an other. The shader code looks remotely like a simple C file with some extra.
Once again, thanks again to Alexandre Mutel, I found an extension for VS2010 which provides syntax colouring for shaders, NShader.
With that shader programs are much easier to read, behold:
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Norm : NORMAL;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float3 Norm : TEXCOORD0;
};
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = mul( input.Norm, World );
return output;
}
So, how does this all work?
From WPF’s point of view, the DirectX code is to be rendered into a Texture2D
and the Texture2D
to be displayed with a D3DImage
.
It starts with:
public class DXImageSource : D3DImage, IDisposable
{
public void Invalidate()
public void SetBackBuffer(SharpDX.Direct3D10.Texture2D texture)
public void SetBackBuffer(SharpDX.Direct3D11.Texture2D texture)
public void SetBackBuffer(SharpDX.Direct3D9.Texture texture)
}
With this subclass of D3DImage
, you can directly set a SharpDX / DirectX Texture2D as the back buffer of the image (Remark that they should be created with ResourceOptionFlags
.Shared, as they will be accessed by the D3DImage
through a shared D3D9
interface).
This ImageSource
could very well be used in an Image
class. But to provide continuous updating, resizing, etc., I created the following FrameworkElement
:
public interface IDirect3D
{
void Reset(ResetArgs args);
void Render(RenderArgs args);
}
public class DXElement : FrameworkElement
{
public DXImageSource Surface { get; }
public IDirect3D Renderer
public bool IsLoopRendering
}
Then the DXElement
does very little by itself. It handles resize event. If IsLoopRendering
is true
, it renders its Renderer every frame. It captures mouse and forwards to the Render
if it implements IInteractiveRenderer
(which D3D does).
And that’s it for the UI.
From the DirectX point of view, I provide a few classes (the D3D tree) that just create an appropriate Device and have virtual method to override to render.
What’s Next?
Direct2D1
only works with Direct3D10
I’d like to make it work with Direct3D11
.
- There are still many things I’d like to know to be reasonably confident, so I (just) started to implement various samples which will show some interesting aspects of DirectX. (1 completed so far.)
Could you get the code?
Well... it’s all on CodePlex!
CodeProject