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 fledges element that supports events. Hooray.

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

Lets see an example

<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>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
And here is the C# code that has the event for the ModelUIElement3D

   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:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }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.

image

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

Advertisements

5 thoughts on “All New .NET 3.5 3D Elements

  1. Jelly Chai says:

    I’m the final year student for Bachelor Science Computer, majoring in Networking.

    I need some help from you, where I wish you can give me the guidelines for how to list out all the computers in the same local network.

    I had copy the code in the codeproject that you posted, but it cannot run. I am new for the C#, therefore I not really know how to use it to write this program. Can you send me the full coding for this program?

    Thank you.

  2. sacha says:

    Wrong place to put this question. But have a look at

    http://pinvoke.net/default.aspx/netapi32.netserverenum

    That has a nice example right there. The method GetServerList(…) returns an ArrayList of computers in local network

    or create a program that runs a dos prompt, and runs the Net Send command, so maybe a BATCH file (.BAT) and pipes that to a txt fle. Then parse the file

    NET PRINT > COMPUTERS.txt

    The COMPUTER.TXT file will then have the following

    Server Name Remark

    ———————————————
    \AIR073
    \RH179LT
    \RH332DT Roger Simpson
    \RH335DT
    \RHOS00476DT
    \RHOS303DT RHOS303DT
    \RHOSOPTIMADT

    Easy to parse me thinks look for each line, then each \ started string, and then a space, and then you have a computer name

  3. Jelly Chai says:

    Sorry, I know that I post at the wrong place, but I really need your help. It prompt out the following error:
    “Program ‘program’ does not contain a static ‘Main’ method suitable for an entry point”

    I do not know how to create the Main method for it after i copy all the coding in the http://pinvoke.net/default.aspx/netapi32.netserverenum.

    Sorry, because disturb, but wish for your help.

    Thank you.

  4. sacha says:

    I suggest you get a copy of C# express 2008 which is free. INstall that. Create a new Windos Forms Application, and it will create a main method in a class called Program.

    I dont really have the time for this, youll have to try stuff out. But that will get you started

  5. George Archer says:

    Dear Mr. Sacha Barber,

    I have a 3D cone (called as “conemodel”) produced by a method. This cone will be rotated in C# code and added to XAML Viewport3D group after rotated by an angle.

    Code Snippet:

    public static void CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2,
    Color color, Viewport3D viewport3d)
    {
    MeshGeometry3D conemesh = new MeshGeometry3D();
    conemesh.Positions.Add(p0);
    conemesh.Positions.Add(p1);
    conemesh.Positions.Add(p2);
    conemesh.TriangleIndices.Add(0);
    conemesh.TriangleIndices.Add(1);
    conemesh.TriangleIndices.Add(2);

    SolidColorBrush brush = new SolidColorBrush();
    brush.Color = color;
    Material material = new DiffuseMaterial(brush);
    GeometryModel3D geometry = new GeometryModel3D(conemesh, material);
    ModelUIElement3D conemodel = new ModelUIElement3D();
    conemodel.Model = geometry;
    viewport3d.Children.Add(conemodel);
    }

    At the last code line, the cone called as “conemodel” will be rotated by 90 deg on the X axes and then it will be added to viewport3d group.

    Could you help me to solve this.

    Kind Regards.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: