WPF 3D - Blender Helps You Getting Productive
The last few days I played around with the 3d capabilities of the Windows Presentation Foundation (WPF). After doing my first steps understanding the basics and and the differences between WPFs 2d and 3D coordinate-systems and painting manual sketches of my primitive 3D objects I found this kind of workflow for producing WPF 3D objects very cumbersome. So I started looking for tools to create the XAML markup for the objects with a tool. Just a few clicks later I found a tool to do complex 3D modeling. The tool is called Blender and is freely available from blender.org.
I followed the quickstart tutorial to find a way through the complex user interface of blender in order to be able to create my first 3D objects which took my abaout 15 minutes. After that I realized that blender offers quite some export modules to export the 3D models into different formats like VRML or X3D. Great I thought, so you probably could create a XAML exporter yourself. But as I'm always late to the scenes of action I also thought that there was already someone else to have the same thought. And indeed, a quick search revealed that Daniel Lehenbauer already created a XAML exporter for blender.
So I downloaded it and tried it. However I had to realize that the exporter doesn't work with the latest version of blender. I digged a bit in the code and identified two basic issues which keep the plugin from working correctly. In order to fix the problem here's a short workaround description:
Identify the definition for the writelamp function
def writeLamp(self, lampObj):
the error is thrown in the line
trace("rot: %f,%f,%f" % (lampObj.rot))
somehow the runtime has problems with the array returned by lampObj.rot. So just replace this line with the following line or just comment it out.
trace("rot: %f,%f,%f" % (lampObj.rot, lampObj.rot, lampObj.rot))
As the exporter was written for a beta release of WPF and some patterns for WPF attributes changed since then the format in which the TriangleIndices are written is not correct therefore I had to define a new function to corrctly format the string. So the best way to fix this is to locate the definition of the listToString() function. Paste the following function definition right below the end of the listToString() function
def tIndicesToString(format, list):
str = ""
comma = ""
for i in xrange(len(list)):
str += comma + format % list[i]
comma = ","
After applying the changes the exporter's basic functionality is restored and you can try the XAML export function.
The easiest option to test is by creating a simple 3D Plane like shown in the picture below (click on the picture to get a larger version)
Then you can use the File --> Export functionality and choose the XAML exporter:
After that you hav a nice XAML file which you can use in your application altogether or only certain portions because it does make sense eventually only to copy the MeshGeometry3D which only contains the 3D coordinates (Positions), the normal vectors (Normals), the indices of the vertices of a sigle triangle (TriangleIndices) and the coordinates for the texture mapping (TextureCoordinates).
In my tests unfortunately I didn't manage to have the exporter write the texture coordinates which can give you some headaches if you specified a texture within blender as this in most cases will result in your model not being rendered correctly or not rendered at all by the WPF runtime. I have to dig deeper into the exporter to find out why it doesn't create the texture coordinates. For now however you can set the coordinates manually like I did in the example here. A guide on how this works was published by Mike Hodnick.
After specifying the texture coordinates the model renders perfectly in WPF.