The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,551,710
since: 19 Jan 2005

3D Data Visualization in WPF Step 1 - Hit-Testing in a 3D ViewPort

posted Mon 06 Mar 06

This blog entry is a sequel to a previous blog entry.

3D hit testing is accomplished in WPF using the VisualTreeHelper.HitTest method. This method has a couple of different overloads, one of which is specifically designed for hit testing 3-D objects. 3D hit testing essentially works the same way that 2D hit testing works, except you essentially project a ray from the camera into the scene, and if a 2D hit test occurs somewhere along that ray, it triggers a hit test result.

When you're hit testing in WPF, you're using an asynchronous callback mechanism. This essentially means that you can respond to multiple hits on the same click without having to do any additional plumbing. For example, if your mouse click actually clicks into two overlapping 3D models, the hit test callback method will fire twice.

Conventional 3D meshes don't provide their own "Click" event handler, which would, of course, make conventional hit testing unnecessary. So we have to trap the Mousedown event from the 3D viewport itself. This will trap and hit test all clicks anywhere in the 3D scene without interfering with any 2D visual elements in the window at the time.

The following code shows the Mousedown event handler for my 3D View Port:

private void ViewPort_MouseDown(object sender, 
 System.Windows.Input.MouseButtonEventArgs args)
{
    Point mouseposition = args.GetPosition(mainViewport);
    Point3D testpoint3D = new Point3D(mouseposition.X, mouseposition.Y, 0);
    Vector3D testdirection = new Vector3D(mouseposition.X, mouseposition.Y, 10);
    PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);
    RayHitTestParameters rayparams = new RayHitTestParameters(testpoint3D, testdirection);
    //test for a result in the Viewport3D
    VisualTreeHelper.HitTest(mainViewport, null, HTResult, pointparams);
}

This code creates a ray from the mouse click position and passes that information as a RayHitTestParameters object to the HitTest method along with the callback method, HTResult. This code is actually in one of the few Feb CTP MSDN examples that actually works properly.

 The next thing you need to do is write the callback function that will be invoked every time the HitTest method finds results:

public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult rawresult)
{
    RayHitTestResult rayResult = rawresult as RayHitTestResult;
    if (rayResult != null)
    {
        RayMeshGeometry3DHitTestResult rayMeshResult = rayResult as RayMeshGeometry3DHitTestResult;
        if (rayMeshResult != null)
        {
            GeometryModel3D hitgeo = rayMeshResult.ModelHit as GeometryModel3D;
     // do something with the model hit, like change
     // colors or start an animation storyboard
        }
    }
    return HitTestResultBehavior.Continue;
}

If you want to stop after the first hit result, then you can simply not return HitTestResultBehavior.Continue, you can instead return HitTestResultBehavior.Stop.

What I ran into here is that this is great if all I want to do is visually affect the model that was clicked. So, if I want to make the model start spinning after you click it, or get brighter, or fire off a complex animation where the object moves around the scene - that's great. But what I'm after is a direct manipulation paradigm, where I'm clicking cubes (or whatever mesh you like) to get at data in a compelling blend of 2- and 3-D interface.

In the example I'm building, each of these cubes is actually going to represent a WCF service hosted by some other user on some computer. When you click the cube, the 3D client will interrogate that service and provide a 2D panel that contains the information that resulted from interrogating the service.

If I am going to interrogate a service in response to clicking a 3D mesh, I need to be able to differentiate between two meshes. A few samples I've seen have compared the geometry... but in this case - I could potentially have a scene with 20 cubes , all of which have the same geometry, and the only thing separating them is the Translate transform that placed them in different positions.

What I really want is IDs or Keys associated with each mesh. Avalon (WPF) doesn't provide for a means for me to access the name or key of a mesh from within the hit testing code. So, what I'm going to do is create a Generics-based Dictionary that contains as its key the mesh itself. The value corresponding to each key will be the unique identifier for the mesh.

First, declare the Dictionary that will contain the mesh IDs:

private Dictionary<GeometryModel3D, string> meshes = new Dictionary<GeometryModel3D,string>();

The following code is how I was dynamically adding cubes to the scene. It shows how I was creating a dictionary with unique identifiers for each mesh contained within it:

// create a couple extra cubes
for (int i = 1; i < 10; i++)
{
    ModelVisual3D extraCube = new ModelVisual3D();
    Model3DGroup modelGroup = new Model3DGroup();
    GeometryModel3D model3d = new GeometryModel3D();
    model3d.Geometry = (MeshGeometry3D)this.Resources["UnitCube"];
    DiffuseMaterial graySide = new DiffuseMaterial(new SolidColorBrush(Colors.White));
    model3d.Material = graySide;
    // Add mesh and identifier..
    meshes.Add(model3d, "Cube " + i.ToString());
    modelGroup.Children.Add(model3d);
    extraCube.Content = modelGroup;     
    mainViewport.Children.Add(extraCube);
    // give the cube a different (cascading) location in the scene
    extraCube.Transform = new TranslateTransform3D(-4 * i, -4 * i, -4 * i);               
}

In the next blog entry, I'll show you how to dynamically show a 2D panel that contains data associated with the 3D mesh that you clicked, that can be obtained from a WIndows Communication Foundation service hosted remotely. What I'm aiming for is direct manipulation and some real 'out of the box' (pun intended) data visualization. I'll also show off one of the cooler BitmapEffects that you can slap onto a panel, the DropShadowEffect.

- The .NET Addict

tags:                  

links: digg this    del.icio.us    technorati    reddit




1. Todd Wilder left...
Mon 11 Sep 06 8:49 pm

I know this is extremely past due, I'm using the RC1 tools, but when I use GetHashCode and compare it to instantiated objects, it seems to work for me.


Tag Related Posts

MobileMe vs. Live Mesh Throwdown - Round 1

Wed 16 Jul 08 10:33 A GMT-05

Building Model Classes in C# and Cocoa

Sun 15 Jun 08 3:13 P GMT-05
tags:            

NYC SharePoint Developer Needed

Mon 12 May 08 12:09 P GMT-05

CLINQ v1.1.0.0 Released!

Fri 02 May 08 5:38 P GMT-05
tags:          

iPhone Underrated as a Gaming Device?

Fri 14 Mar 08 1:50 P GMT-05
tags:        

One Framework to Rule them All

Mon 25 Feb 08 6:49 P GMT-05

CLINQ v1 Demo - Network Message Filtering

Wed 09 Jan 08 7:47 P GMT-05
tags:        

Building a Ledger Style for WPF Grids

Tue 21 Aug 07 3:30 P GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

My 2008 Wishlist : A Transformers MMORPG

Tue 26 Jun 07 12:04 P GMT-05
tags:        

The dreaded language bleed-over has begun

Tue 19 Jun 07 6:23 P GMT-05
tags:        

My first "Acropolis" Application

Mon 04 Jun 07 1:40 P GMT-05
tags:      

Exploring the Delegate Design Pattern

Mon 14 May 07 6:30 P GMT-05

Core Data - Almost too Easy?

Wed 18 Apr 07 2:23 P GMT-05

Will Silverlight be DOA?

Mon 16 Apr 07 8:02 P GMT-05

Exploring the MVC Pattern in WPF

Tue 10 Apr 07 12:51 P GMT-05
tags:                      

My Little Pony .NET Unleashed 2007

Fri 30 Mar 07 1:59 P GMT-05

An experience with the Leopard beta

Mon 26 Mar 07 7:45 P GMT-05
tags:                

Authorness

Thu 15 Mar 07 1:44 P GMT-05

WPF Bindings == WTF Bindings?

Mon 12 Mar 07 6:31 P GMT-05

On MUDs

Thu 08 Mar 07 5:00 A GMT-05
tags:                    

Cocoa Programming vs. WPF : NIB vs XAML

Tue 20 Feb 07 2:09 P GMT-05

Cocoa Bindings vs. WPF Binding

Thu 15 Feb 07 5:41 P GMT-05
tags:                

Ulysses Agenda Makes Redmond Developer News

Wed 29 Nov 06 7:10 P GMT-05
tags:                

Is the continuous beta the new model for Vista?

Tue 21 Nov 06 8:51 P GMT-05
tags:              

A visit to Nintendo World on "Wii Day"

Mon 20 Nov 06 12:37 P GMT-05
tags:          

Ulysses Agenda - Network Engine Test 1

Mon 09 Oct 06 2:26 A GMT-05
tags: