WPF 3D Hit Test method VisualTreeHelper.HitTest()

How to do 3D hit testing has come up a bit recently in the forums but essentially it isn’t any different than 2D hit testing which is described on MSDN here. You can either start with a 2D point on the Viewport3D or a 3D point on a Visual3D.

Starting at the Viewport3D level is straightforward. Suppose you have a mouse down handler and you want it to hit test into 3D:

public void MouseHitTest(object sender, MouseButtonEventArgs args)
{
    Point mousePos = args.GetPosition(viewport3d);
    PointHitTestParameters hitParams = new PointHitTestParameters(mousePos);
    VisualTreeHelper.HitTest(viewport3d, null, ResultCallback, hitParams);
}
Three constructure for HitTest:
HitTest(Visual, Point) --- Returns the topmost Visual object of a hit test by specifying a Point.
HitTest(Visual3D, HitTestFilterCallback, HitTestResultCallback, HitTestParameters3D)  --- Initiates a hit test on the specified Visual3D
HitTest(Visual, HitTestFilterCallback, HitTestResultCallback, HitTestParameters) --- Initiates a hit test on the specified Visual(2D)

Visual3D is slightly trickier because a point is no longer sufficient in 3D space. You also need to specify a direction. An origin point plus a direction is known as a ray. It will look something like this:

    RayHitTestParameters hitParams = 
        new RayHitTestParameters(
            new Point3D(0, 0, 0),
            new Vector3D(1, 0, 0)
            );
    VisualTreeHelper.HitTest(visual3d, null, ResultCallback, hitParams);

The only difference is the HitTestParameters.

The second argument to HitTest is a filter which allows you to control which parts of the tree get tested. Skipping part of the tree is a perf win of course, but generally you’ll want to hit test everything and this is covered well in the MSDN article so I won’t do it here.

The third argument, the result callback, is where the action happens. We’ve hit something and we’ve decided to tell you about it. It could be 3D or it could be 2D. It’s up to you to decide what you’re looking for and when/if you want to stop.

public HitTestResultBehavior ResultCallback(HitTestResult result)
{
    // Did we hit 3D?
    RayHitTestResult rayResult = result as RayHitTestResult; 
    if (rayResult != null) 
    { 
        // Did we hit a MeshGeometry3D?
        RayMeshGeometry3DHitTestResult rayMeshResult = 
            rayResult as RayMeshGeometry3DHitTestResult;
                                                                                          
        if (rayMeshResult != null) 
        { 
            // Yes we did!
        } 
    } 
    
    return HitTestResultBehavior.Continue; 
}

RayMeshGeometry3DHitTestResult has MeshHit, PointHit, and DistanceToRayOrigin properties which tell you pretty much everything you want to know. It also has the triangle indices and weights (a.k.a. barycentric coordinates) so you can do things like figure out the texture coordinate of the point hit.

Performance Tip: As you mouse over 3D we do hit testing behind your back because there could be interactive 2D on the 3D or a 2D layer underneath the 3D (empty Viewport3D space is considered transparent for hit testing purposes). If you know you don’t need either of those, disable hit testing on the Viewport3D by setting its IsHitTestVisible property to false. This is an old tip but a good one :)

Sneaky Performance Tip: Can’t disable hit testing and it’s still eating up a bunch of CPU? Override HitTestCore() and, while the mouse is moving, only really issue the hit test every two or three (or more!) requests. This will introduce lag of course but that may be acceptable to your application.

 

From: http://blogs.msdn.com/wpf3d/archive/2009/05/18/3d-hit-testing.aspx

 

 

 

    VisualTreeHelper class 是一个 static helper class ,它提供了在运行环境管理Visual和 Visual3D objects 的功能.

VisualTreeHelper class 提供了可视化对象之间的Hit Testing的方法.
 
 
Enumerating the Visual Tree
VisualTreeHelper class 提供了枚举visual tree的成员的功能。得到父节点。调用GetParent 方法. 取得孩子节点, 或者可视对象的直接后继,调用 GetChild 方法.
visual tree可以使用下面的算法,很容易的遍历
C#
// Enumerate all the descendants of the visual object.
static public void EnumVisual(Visual myVisual)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
    {
        // Retrieve child visual at specified index value.
        Visual childVisual = VisualTreeHelper.GetChild(myVisual, i);
 
        // Do processing of the child visual object.
 
        // Enumerate children of the child visual object.
        EnumVisual(childVisual);
    }
}
 
VisualTreeHelper class 提供了返回可视对象包围矩形的方法。可以调用GetContentBounds返回可视对象包围矩形. 还可以返回visual object 的所有子孙的包围矩形,需要调用GetContentBounds. 下面的代码显示了怎么计算一个可视对象和它的所有子孙的包围矩形。
C#
// Return the bounding rectangle of the parent visual object.
Rect rectBounds = VisualTreeHelper.GetContentBounds(parentVisual);
 
// Expand the rectangle to include the bounding rectangle
// of the all of the visual object's descendants.
rectBounds.Union(VisualTreeHelper.GetDescendantBounds(parentVisual))


From:http://blog.csdn.net/Net_Ghost/archive/2006/06/10/787428.aspx

你可能感兴趣的:(WPF 3D Hit Test method VisualTreeHelper.HitTest())