Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

All New .NET 3.5 3D Elements

5.00/5 (3 votes)
17 Jun 2009CPOL 16.8K   153  
All new .NET 3.5 3D elements

I have started looking at 3D again in WPF. I have in the past blogged about the Viewport2DVisual3D 3D WPF element. Well for what I am working on, I didn’t need to be able to put 2D interactive elements on a 3D surface, but I did want the 3D object to able to respond to Mouse events.  Now in the past, what you would have done is use a MouseDown event on the Viewport3D and do some sort of hit testing. Which was ok….

But now, there is the wonderful new .NET 3.5 element ModelUIElement3D which is a fully fledged element that supports events. Hooray!

And there is also a new container element to host 1 or more ModelUIElement3D elements.

Let's see an example:

XML
<Window x:Class="Shapes.Window1″
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Shapes"
    Title="Window1″ Height="610.122″ Width="633.46″>

    <Window.Resources>

        <!– The 3D cube –>
        <MeshGeometry3D x:Key="CubeMesh"
            TriangleIndices = "0,1,2     2,3,0
                               4,7,6     6,5,4
                               8,11,10   10,9,8
                               12,13,14  14,15,12
                               16,17,18  18,19,16
                               20,23,22  22,21,20″

             Positions      = "-1,-1,1   -1,-1,-1  1,-1,-1  1,-1,1
                               -1,1,1    -1,1,-1   1,1,-1   1,1,1
                               -1,-1,1   -1,1,1    1,1,1    1,-1,1
                               -1,-1,-1  -1,1,-1   1,1,-1   1,-1,-1
                               -1,-1,1   -1,1,1   -1,1,-1  -1,-1,-1
                                1,-1,1    1,1,1    1,1,-1   1,-1,-1″ />
    </Window.Resources>

    <Viewport3D>

        <Viewport3D.Camera>
            <PerspectiveCamera x:Name="camera" Position="-2,2,5″
                               LookDirection="2,-2,-5″ FieldOfView="90″ />
        </Viewport3D.Camera>

        <!– Container for 3D Elements –>
        <ContainerUIElement3D x:Name="container">
            <ContainerUIElement3D.Transform>
                <RotateTransform3D>
                    <RotateTransform3D.Rotation>
                        <AxisAngleRotation3D Axis="0, 1, 0″ Angle="0″ />
                    </RotateTransform3D.Rotation>
                </RotateTransform3D>
            </ContainerUIElement3D.Transform>

            <!– A fully Fledged 3d element complete with routed events >
            <ModelUIElement3D MouseDown="Cube1_MouseDown">
                <ModelUIElement3D.Transform>
                    <Transform3DGroup>
                        <TranslateTransform3D OffsetZ="1.5″ />
                        <RotateTransform3D>
                            <RotateTransform3D.Rotation>
                                <AxisAngleRotation3D Axis="0, 1, 0″ Angle="0″ />
                            </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                    </Transform3DGroup>
                </ModelUIElement3D.Transform>
                <ModelUIElement3D.Model>
                    <GeometryModel3D Geometry="{StaticResource CubeMesh}">
                        <GeometryModel3D.Material>
                            <DiffuseMaterial x:Name="cube1Material" Brush="Blue" />
                        </GeometryModel3D.Material>
                    </GeometryModel3D>
                </ModelUIElement3D.Model>
            </ModelUIElement3D>
        </ContainerUIElement3D>

        <ModelVisual3D>
            <ModelVisual3D.Content>
                <DirectionalLight Color="White" Direction="-1,-1,-1″/>
            </ModelVisual3D.Content>
        </ModelVisual3D>

    </Viewport3D>

</Window>

And here is the C# code that has the event for the ModelUIElement3D.

C#
 1:  using System;
 2:  using System.Collections.Generic;
 3:  using System.Linq;
 4:  using System.Text;
 5:  using System.Windows;
 6:  using System.Windows.Controls;
 7:  using System.Windows.Data;
 8:  using System.Windows.Documents;
 9:  using System.Windows.Input;
10:  using System.Windows.Media;
11:  using System.Windows.Media.Animation;
12:  using System.Windows.Media.Media3D;
13:  using System.Windows.Media.Imaging;
14:  using System.Windows.Navigation;
15:  using System.Windows.Shapes;
16:
17:  namespace Shapes
18:  {
19:      /// <summary>
20:      /// Interaction logic for Window1.xaml
21:      /// </summary>
22:      public partial class Window1 : Window
23:      {
24:
25:
26:          public Window1()
27:          {
28:              InitializeComponent();
29:          }
30:
31:
32:          /// <summary>
33:          /// 3d Element Mouse Event, Neat
34:          /// </summary>
35:          private void Cube1_MouseDown(object sender, MouseButtonEventArgs e)
36:          {
37:              ModelUIElement3D currentObject = sender as ModelUIElement3D;
38:              if (currentObject.Transform is Transform3DGroup)
39:              {
40:                  RotateTransform3D rotateTrans = null;
41:
42:                  Transform3DGroup transGroup =
43:                      currentObject.Transform as Transform3DGroup;
44:                  rotateTrans = TryFindChild<RotateTransform3D>(transGroup);
45:                  if (rotateTrans != null)
46:                  {
47:                      // spin the object around
48:                      DoubleAnimation doubleAnimation =
49:                          new DoubleAnimation(0,360,
50:                          new Duration(TimeSpan.FromSeconds(0.5)));
51:                      rotateTrans.Rotation.BeginAnimation(
52:                          AxisAngleRotation3D.AngleProperty, doubleAnimation);
53:                  }
54:              }
55:          }
56:
57:
58:          /// <summary>
59:          /// Try and find child of type T in the Transform3DGroup
60:          /// </summary>
61:          public static T TryFindChild<T>(Transform3DGroup parent)
62:            where T : DependencyObject
63:          {
64:              foreach (DependencyObject child in parent.Children)
65:              {
66:                  if (child is T)
67:                  {
68:                      return child as T;
69:                  }
70:              }
71:              return null;
72:          }
73:
74:
75:      }
76:  }

And that is all there is to it. So in this example, if the cube gets a MouseDown, I lookup its RotateTransform3D and spin it around by 360 degrees.

37354/image-thumb6.png

And here is a zip file with the demo project code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)