Create 3D WPF Models using XAML Exporter for Blender

You can create 3D meshes for XAML applications using Blender (which is free open-source 3D content creation software that can run on Windows, Linux, Mac OS X and other operating systems, currently at version 2.48a) combined with the XAML Exporter for Blender (a free open-source add-on script released separately under a slightly different license, currently at version 0.47, written by Daniel Lehenbauer and updated by Robert Hogue). For those who don’t know, Blender was used to create the free Big Buck Bunny movie. The following example shows the basics of what can be accomplished, starting with screenshots of the initial 3D model in Blender and the resulting WPF application using the exported data.

Screenshot of Blender with 3D model to be exported as XAML.

Screenshot of WPF Application using the 3D model exported as XAML from Blender.

For this example, we use the Plant model of Sebi (available from The Official Blender Model Repository), which consists of a single file named plante.blend that was opened in Blender and is shown in the first image. After opening the file, select all the items (press the A-key twice, first to unselect the current object, and a second time to select and highlight everything), then export the scene using the menu by selecting File | Export | Xaml (.xaml)... and click on the Export Xaml button. (That is the menu item that is added by installing the XAML Exporter script.) The exported XAML file, generated with the default filename of plante.xaml, looks something like the following:

<Viewport3D 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Viewport3D.Camera>
    <PerspectiveCamera  UpDirection="0,1,0" LookDirection="0,0,-1"
        FarPlaneDistance="100.000000" NearPlaneDistance="0.100000" 
        Position="0,0,0" FieldOfView="49.134343">...</PerspectiveCamera>
  </Viewport3D.Camera>
  <ModelVisual3D>
    <ModelVisual3D.Content>
      <Model3DGroup>
        <Model3DGroup x:Name="MG_Feuilles_001_Plane_01">
          <Model3DGroup.Transform>...</Model3DGroup.Transform>
          <GeometryModel3D x:Name="OB_Feuilles_001_Plane_01">
            <GeometryModel3D.Material>
              <DiffuseMaterial x:Name="MA_Feuilles">
                <DiffuseMaterial.Brush>
                  <SolidColorBrush Color="#0c7114"/>
                </DiffuseMaterial.Brush>
              </DiffuseMaterial>
            </GeometryModel3D.Material>
            <GeometryModel3D.BackMaterial>...</GeometryModel3D.BackMaterial>
            <GeometryModel3D.Geometry>
              <MeshGeometry3D x:Name="ME_Feuilles_001_Plan"
                  Positions="0.013062 -0.063477 0.05956 ... "
                  Normals="-0.900327 -0.434126 -0.030427 ... "
                  TextureCoordinates=""
                  TriangleIndices="0 1 2 ... 85116 85118 85119" />
            </GeometryModel3D.Geometry>
          </GeometryModel3D>
        </Model3DGroup>
        <Model3DGroup x:Name="MG_Lamp">...</Model3DGroup>
        <Model3DGroup x:Name="MG_Lamp_001">...</Model3DGroup>
        <Model3DGroup x:Name="MG_Plane">...</Model3DGroup>
        <Model3DGroup x:Name="MG_Pot_de_fleurs_002_Tub">...</Model3DGroup>
      </Model3DGroup>
    </ModelVisual3D.Content>
  </ModelVisual3D>
</Viewport3D>

When you export other models, the XAML might need some further editing; as is often the case when converting 3D models from one format to another, the textures and lighting are not always preserved. The model used for the present example doesn’t have any fancy textures and uses simple colored materials, such that it converts more easily, but the lighting will be tweaked later in code (for example, Blender’s hemi-light does not get exported, which is the content of the Model3DGroup element named MG_Lamp_001 in the Plant model that is subsequently modified).

The exported XAML can now be consumed, and for the example we can simply create a new C# Project in Visual Studio using the standard WPF Application template. Replace the auto-generated C# code of the Window class with the following. (Although it is not strictly necessary, I changed the name of the class from Window1 to MainWindow, and I also changed the namespace to something more appropriate.)

using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Media3D;
 
namespace TiaanDotCom.Samples.XamlExporterForBlender.WpfApplication
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            // Perform basic initialization of this WPF window
            InitializeComponent();
            this.Title =
                "WPF Application using 3D XAML Exported from Blender";
            this.Width = 440;
            this.Height = 300;
 
            // Load the XAML file produced by XAML Exporter for Blender
            Viewport3D model;
            using (FileStream fileStream = File.OpenRead(@"plante.xaml"))
            {
                model = (Viewport3D)(XamlReader.Load(fileStream));
            }
 
            // Tweak the lighting of the example's exported scene
            model.Children.Add(new ModelVisual3D() { 
                Content = new AmbientLight(Colors.DarkKhaki * 0.05f) });
            ((Model3DGroup)(model.FindName("MG_Lamp_001"))).Children.
                Add(new SpotLight() { Color = Colors.White * 0.825f });
 
            // Add the 3D model meshes to a page inside this WPF window
            this.Content = new Page()
            {
                Background = Brushes.CornflowerBlue,
                Content = model
            };
        }
    }
}

Not much code is needed to load the exported XAML file and display the mesh; the comments in the code explain the detail of what is actually done. You may need to include the path to the exported plante.xaml file, or add the file as a Content item to the Project to be copied to the output directory during a build. Compiling and running the WPF application result in what has been shown in the second screenshot above.

Download: MainWindow.xaml.cs (1.43 KB)

Comments

XAML Exporter version 0.48

TheRHogue released version 0.48 of the XAML Exporter for Blender earlier today. It incorporates the fix that I submitted for the “RuntimeError: could not find object's selection state” error message I encountered a while back, which happens if you try to determine the Object’s selection state for any Blender object that is not part of the current scene. This can happen, for example, by accessing the object’s sel variable or isSelected() function, after getting access to a non-current-scene object through the Blender.Object.Get() function on a multi-scene Blender file. Note that the Blender 2.48 API documentation for the Blender.Object.Get() function incorrectly states that it returns “a list with all Objects in the current scene” and that the contradicting note further down is actually correct, saying it “will return objects from all scenes”. If you only want a collection of objects for the current scene, you need to use the objects instance variable of the current Scene instead, for example by using Blender.Scene.GetCurrent().objects. Similar incorrect statements are made about Get() functions of other Blender modules (such as for World, Image, Camera, Material, and more), while the actual behavior is documented correctly for only a few modules (for example, Font and Group).

By the way, I only realized today that Robert Hogue (a.k.a. TheRHogue) was in fact the Technical Editor of Adam Nathan’s excellent book on WPF, titled “Windows Presentation Foundation Unleashed”. I wish that all software-development books were written to such a high standard!

Thanks

Thanks for this article. I tried to find a tool for creating 3D models and exporting them in WPF. The first application I found was ZAM 3D.

The second link, Google gave to me, was your article. I also like Blender so this script should be very helpful for me.