Nuaj [nu-a-j'] is my little .Net renderer for DirectX 10. It's quite small and really easy to use. Source code is available here and it's free.
If you want to use it, you will need the SlimDX .Net wrapper that tightly wraps DirectX for use into .Net managed code. Also, it was created with Visual Studio 2010 and .Net Framework 4.0 so make sure you have that !
The main idea behind Nuaj is to "make my life easier", not to create the ultimate renderer that washes dishes and serves coffee. Those are never finished and you always come up with a bad surprise once it's time to use it (providing that you reach that point).
So I decided to create first a set of basic helpers to manage my stuff. Basically, all I need is to create geometry easily using vertices and/or indices, I need to create materials from shaders that compile either from memory or from file, I need to create textures and render targets to feed my shaders and rendering pipeline, tie all this together and roll the dice...
Just so you see how easy it is to write your own demo with Nuaj (and so you will want to read on to the end of that page), here is the basic code you'll have to write to render a textured cube (I skipped the shader code here) :
// Create the cube material m_CubeMaterial = new Material<VS_P3C4T2>( m_Device, "CubeMaterial", new System.IO.FileInfo( "./FX/CubeShader.fx" ) ); // Create the cube primitive VS_P3C4T2[] Vertices = new VS_P3C4T2[] { new VS_P3C4T2() { Position=new Vector3( -1.0f, -1.0f, -1.0f ), Color=new Vector4( 0.0f, 0.0f, 0.0f, 1.0f ), UV=new Vector2( 0.0f, 0.0f ) }, new VS_P3C4T2() { Position=new Vector3( +1.0f, -1.0f, -1.0f ), Color=new Vector4( 1.0f, 0.0f, 0.0f, 1.0f ), UV=new Vector2( 1.0f, 0.0f ) }, new VS_P3C4T2() { Position=new Vector3( +1.0f, +1.0f, -1.0f ), Color=new Vector4( 1.0f, 1.0f, 0.0f, 1.0f ), UV=new Vector2( 1.0f, 1.0f ) }, new VS_P3C4T2() { Position=new Vector3( -1.0f, +1.0f, -1.0f ), Color=new Vector4( 0.0f, 1.0f, 0.0f, 1.0f ), UV=new Vector2( 0.0f, 1.0f ) }, new VS_P3C4T2() { Position=new Vector3( -1.0f, -1.0f, +1.0f ), Color=new Vector4( 0.0f, 0.0f, 1.0f, 1.0f ), UV=new Vector2( 0.0f, 0.0f ) }, new VS_P3C4T2() { Position=new Vector3( +1.0f, -1.0f, +1.0f ), Color=new Vector4( 1.0f, 0.0f, 1.0f, 1.0f ), UV=new Vector2( 1.0f, 0.0f ) }, new VS_P3C4T2() { Position=new Vector3( +1.0f, +1.0f, +1.0f ), Color=new Vector4( 1.0f, 1.0f, 1.0f, 1.0f ), UV=new Vector2( 1.0f, 1.0f ) }, new VS_P3C4T2() { Position=new Vector3( -1.0f, +1.0f, +1.0f ), Color=new Vector4( 0.0f, 1.0f, 1.0f, 1.0f ), UV=new Vector2( 0.0f, 1.0f ) }, }; int[] Indices = new[] { 0, 2, 1, 0, 3, 2, 4, 5, 6, 4, 6, 7, 0, 4, 7, 0, 7, 3, 1, 6, 5, 1, 2, 6, 0, 1, 5, 0, 5, 4, 3, 7, 6, 3, 6, 2 }; m_Cube = new Primitive<VS_P3C4T2,int>( m_Device, "Cube", PrimitiveTopology.TriangleList, Vertices, Indices, m_CubeMaterial ); // Create the cube diffuse texture Image<PF_RGBA8> DiffuseImage = new Image<PF_RGBA8>( m_Device, "Diffuse", Properties.Resources.TextureBisou ); // Here you can provide any kind of Bitmap m_CubeDiffuseTexture = new Texture2D<PF_RGBA8>( m_Device, "Diffuse Texture", DiffuseImage, 1, true );
And the rendering code goes like this :
// Clear m_Device.ClearRenderTargetView( m_Device.DefaultRenderTarget, Color.CornflowerBlue ); // Draw m_Cube.Draw(); // Show ! m_Device.Present();
Helpers
All helpers in Nuaj derive from a base Component class that takes a Device and a Name as basic parameters for construction.
- Device, the Device helper is a singleton and wraps the DX10 Device. It contains a swap chain and a back buffer (the default render target). The standard DirectX Device methods are rewired through that new Device class.
Basically, nothing fancy here, you just create your Device with specific parameters and call "ClearRenderTarget()" and "Present()" to run the show. The Device is the first parameter needed for every other component type in Nuaj so make sure it's created first.
- Material, the Material helper is really neat ! It's a template against a #Vertex_Structures and compiles a shader from a string, a byte[] or from a file.
In the latter case, it automatically watches the file for changes so your shader is recompiled every times the file changes (ideal for debugging !). It also supports a default "Error Shader" when your shader fails to compile. The material also supports what I call "Shader Interfaces" (more on that here #Shader_Interfaces) which are reeeaaally useful !
- VertexBuffer, this wraps an old-style VertexBuffer (VB) and accepts creation from a bunch of vertices that are organized as an array of #Vertex_Structures. This type is also a template against #Vertex_Structures and only a VertexBuffer with vertices compatible with the vertex structure used by a material can be used to render with such a material.
It contains a "Draw()" method that will render a non-indexed primitive using the vertices stored by the VB.
- IndexBuffer, this wraps an old-style IndexBuffer (IB) and accepts creation from a bunch of Indices that are organized as an array of shorts, ushorts, ints or uints.
It contains a "Draw()" method that will render an indexed primitive using the indices stored by the IB.
- Primitive, this is simply a helper that gathers a VertexBuffer and a Material, and also an optional IndexBuffer.
It contains a "Draw()" method that will render the primitive using the specified Material and that will draw either an indexed primitive if an IndexBuffer exists or a non-indexed primitive otherwise. Typically, objects exported from a 3D package should create a bunch of Primitives for their objects, each should then render in turn. NOTE: Materials can be assigned to multiple primitives, there are no restrictions on that.
- Image, this is not basically a DirectX component per-se but rather a helper to load and convert standard LDR or HDR images into a "DataRectangle", which is then readable by a texture.
- Texture2D, this wraps a 2D readonly texture (i.e. what DirectX calls "immutable" resource).
These textures are readonly from the GPU only and not accessible by the CPU. They are the most common texture types for rendering and must be provided with initial data (i.e. an Image) at the time of initialization, there is no delay-loading of these ones.
- RenderTarget, this wraps a 2D read/write texture (i.e. what DirectX calls "default" resource) that is also able to be rendered to.
These textures are also fairly common
Vertex Structures
Pixel Formats
Shader Interfaces
.Net Subtlety
If you create a new application from scratch and wish to use SlimDX, make sure to edit you app.config file and change from these lines :
<?xml version="1.0"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>
to these ones so you can use backward compatible assemblies :
<?xml version="1.0"?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>