Getting started with 3D in WPF

Though WPF is not meant for complex 3D implementations, the Viewport3D is a quite powerful feature. You can implement small 3D Animations to improve your design, the usability and so on.

However, the usage of this Viewport3D is not easy going. Usually (at least I do) you have created an 3D Object in a 3D Modeling Application such as 3DS MAX or Cinema 4D and now you want to import it into your WPF Application. The Viewport3D accepts vectors, so for example you can export your object to a XAML (those plugins usually are not for free) and then somehow fiddle it into there. Fortunately there is the Helix Toolkit which is making life a lot easier!

I will show you how to get started from scratch and how to import and move Objects.

Setting up a new VS Project

First of course we need a new Visual Studio C# WPF Project, I don't know which Version is required for the Helix toolkit, I tested it with VS2012 and VS2013 on .NET 4.5 which both worked fine.

Now we need the Helix Toolkit, you can either use NuGet or download the binaries from here I will explain how to do it with NuGet briefly. Right click on the Project in the Project Explorer->manage NuGet Packages, search for helix and install the toolkit and the WPF package.

Unbenannt

thats it 😉

Preparing the 3D Objects

So now that we have the Helix Toolkit installed we can take care of the 3D Model. For this example I will use one of the most remarkable things on earth, the human body. Fortunately there are very detailed 3D models freely available on the web. I will use this feller here for the use with Cinema 4D, this is just an example, if you have no access to Cinema 4D don't worry.

After the Model had been loaded into Cinema 4D (may take some while) we can take away all the unwanted "parts". I want to make it possible to move the arms with 2 sliders in WPF, so we need a few bones, the skeleton itself, the upper arms (lat.Humeri) and the lower arms (lat. antebrachia). The model unfortunately has the left and right bones in one object, so we need to fix this.

Here you can see the groups I created:

Skeleton.obj

Skeleton.obj

Now I separate the 2 sides sinister is latin for left and dexter means right (at least thats what I believe)

Unbenannt

In the next step we prepare the bones to be imported into the Helix Toolkit.
All the different groups need to be saved into single files. So we simply copy each bone (or group of bones) into an own project and export it. Those are the groups which will be moved later on. So in this case we have 5 Groups:

  • Skeleton
  • humerus sinister/dexter
  • antebrachium sinister/dexter

I created a folder in the VS Project called "bones" where those 5 files will go to. I have started with the Skeleton, copy the bones into a new project and do NOT change anything, otherwise the bones will not fit when we try to recombine them. Simply export the project to a ".obj" file (File->Export), leave all settings on default. Helix accepts different formats, I have tried also 3ds which also worked fine.

We end up with 5 files:

Unbenannt

skeleton.obj

humerus_sinister.obj

humerus_sinister.obj

humerus_dexter.obj

humerus_dexter.obj

antebrachium_sinister.obj

antebrachium_sinister.obj

antebrachium_dexter.obj

antebrachium_dexter.obj

You may note that the Material has changed, this is because the .obj format has no properties for materials as a .c4d file for instance. However, you might want to use a format which is supporting color (e.g. 3ds). Its also possible to change the material in code.

Importing the Objects into Visual Studio

Now we want to import the .obj files into WPF. Thanks to the Helix Toolkit this is easy.
As the .obj files now belong to the project we need to add them to the Solution Explorer, therefore we need to click "show all files" and then right click on "bones" and "include in project". Then we need to make sure that the files in "bones" are always copied to the output directory if there is a new version available.

Unbenannt

Unbenannt

Great! Now we can start coding!

The coding part

In this example I will keep it simple by not creating own classes and instead make everything happen in the "MainWindow.xaml.cs", this is not a good stile but I think for this example its sufficient.

I defined a few global variables which represent the parts of our 3D Model.

First we need a  Model3DGroup skeleton;  which is representing the group of our 5 "independant" parts. Now that we have the group we need the 3D Models itself:

In the Constructor of the "MainWindow" we also define a "ModelImporter" which is loading our .obj files. We end up with:

Now its a good time to to hit "Start" to see if there had been any errors. Make sure you click through the Exception tree to find the root cause which is most likely that there was a typo or you have not copied the file to the output directory. If it is startable we can move on.

On the "MainWindow.xaml" we now need to add the parts we need. But first things first, first we need a reference to the Helix Toolkit  xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf" . Now we can add 4 Sliders and a "HelixViewport3D". I copied the source from on of the Helix Samples and modified it slightly.

You can see that we have a few bindings. I bind the slider values the movement of the arms and the "ModelVisual3D" is binded to a model called "our_Model", those variables have not been defined in code yet so lets move on.

Back at "MainWindow.xaml.cs" we need to add "our_Model", it need to be public so it is accessible by the GUI and needs to have a setter and getter in order to be bindable.

back in the constructor we need to add the 3D Models to the group, set the data context of the viewport and assign our group of objects to "our_Model".

To sum it up, we have 5 bones/objects which we group to one "Model3DGroup" and then assign this group to a public accessible 3D Object.
Now its time to give it a try:

Unbenannt

Its doing something! But... its blue... and its laying on the ground. Well but before going further first lets see how to control that view. On the lower right you have a small cube which you can use for navigation by simply clicking the sides of the cube.

Before you try to use the mouse or the keyboard to move the object make sure it has the focus by clicking on it. You can use the arrow key or the mouse to move it.

Use the Arrow keys to move around the object and press "SHIFT" simultaneously to change the center, use "CTRL" to move slowly. Use the Mouse wheel to zoom or "CTRL" and the mouse. You can use the mouse to freely look around by holding the right mouse button and move around, press "SHIFT" simultaneously to change the center. This is just a brief description, there are more controls available.

First lets get rid of this blue color. You can either go for another file format such as "3ds" to include the color there or you set the color when you import a file. It is possible to change the color after the 3DModel had been created but I have not figured out how to do it. However, lets go for the dummy approach 😉

Will result in:

Unbenannt

The fact that the skeleton is "laying" and not standing upright has to do with the files we have exported, so either you rotate the skeleton in C4D or you transform the skeleton in Code.

Lets do it in Code so we have a good starting point to talk about transformations.
If we want to rotate something we need 3 things.

  • A Point where the center of rotation is
  • A vector which is describing in which direction the axis points
  • An angle
A small helper to find points in the 3D world

We can use the cube on the bottom right to get an idea where X,Y and Z are and therefore the vector is easy but how to get the point on which we want to rotate? Im sure you somehow can figure that out by checking the size of the objects but I did it the "dummy way" by placing a small cube in the 3D world which I can move around, this way I can move it until it is at the desired point and simply look up the coordinates.

So first I add a small grid with some controls, I love the "Extended WPF toolkit" (NuGet) and I installed it to have some nice numeric controls, if you don't like it, choose a control of your choice. If you go for the "Extended WPF toolkit" don't forget to add  xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" to the XAML header after the installation. The code for the Grid is:

Now that we have the controls we need to have an object to move around. I took a box for that.

And now the parameters, the box does not support binding therefore my dummy solution:

now there is a small cube which we can resize and move around.

Unbenannt

So it seems like we have already found our point and vector to move the skeleton. Now we can rotate it:

We rotate on the X axis and the Point is 0,0,0. Its good practice to play around with those values so you will get an idea what is going on.

Unbenannt

Now we only need to find the point where we want to rotate the humeri.

Lets start with the left Humerus

I'm not a physician but it seems to be ok:

Unbenannt

In Code:

Wait! What? why is Y and Z flipped and Z is negative?
Remember when we rotate the whole thing? Its the WHOLE thing, including its points. As we have rotated on the X axis on Point 0,0,0 this calculation is easy. For others its a bit more tricky. Luckily there is a way out. Either you measure the points before the transformation or you write a small helper which could look like this:

This will rotate the point back by 90 degree and we get the point we looking for.For small Objects a helper like this might be useful but for more complex ones it is a pain.

Lets move on to the antebrachium sinister as somehow this looks a bit strange right now:

Unbenannt

Note that as we have a different vector the movement is now 45°

So every time we move the humerus we also need to move the antebrachium, well thats easy:

But now things start to get interesting if we want to rotate the antebrachium.

The point we rotate around is changing every time the humerus moves, therefore we need to recalculate it every time we move.

Now the same thing for the other side and this is the result

Unbenannt

Thats it

Though I'm very sure that there are better and more elegant ways to do it I think that this should be a good starting point as the main challenges and techniques had been discussed. Have fun with WPF and 3D 😉

Code

XAML

C#

 

9 thoughts on “Getting started with 3D in WPF

  1. Thank you so much for this great article. It helped me a lot in moving forward with the 3D stuff in WPF.

  2. You are welcome!

  3. arash

    hi Thomas;
    how about vb.net ?
    can we do this in vb ?

  4. Vahed

    Hi
    Thank you, that's great.
    Please insert download link for .obj files beacuse I don'tm have no access to Cinema 4D to export objects. It's better to upload all your project.
    Best regards.
    Vahed Mamqaderi

    • Hello Vahed,

      due to copyright issues I can not upload the bones. I can offer you some more neutral .obj files to get started.

  5. aaa

    Hello.
    Can I also load .step files using helix toolkit? or convert them into .obj file?
    Thanks.

  6. […] Getting started with 3D in WPF […]

  7. […] Getting started with 3D in WPF […]

Leave a Reply

About Thomas Barth

Thomas Barth, born 1986, is a german teaching fellow and Ph.D. student. He studied electrical engineering in Darmstadt, Frankfurt and Helsinki and worked 7 years in industry automation before he switched to embedded systems and microelectronics. To read more about him, click here.