2

I'm writing a WPF application that displays terrain in 3D.

When I perform hit testing, the wrong 3D point is returned (not the point I clicked on).

I tried highlighting the triangle that was hit (by creating a new mesh, taking the coordinates from the RayMeshGeometry3DHitTestResult object). I see that the wrong triangle gets hit (a triangle is highlighted, but it is not under the cursor).

I'm using a perspective camera with field of view of 60, and the near and far planes are of 3 and 35000 respectively.

Any idea why it might happen and what I can do to solve it?

Let me know if you need any more data.

Edit: This is the code I use to perform the hit testing:

private void m_viewport3d_MouseDown(object sender, MouseButtonEventArgs e)
{
    Point mousePos = e.GetPosition(m_viewport3d);
    PointHitTestParameters hitParams = new PointHitTestParameters(mousePos);
    HitTestResult result = VisualTreeHelper.HitTest(m_viewport3d, mousePos);
    RayMeshGeometry3DHitTestResult rayMeshResult = result as RayMeshGeometry3DHitTestResult;
    if (rayMeshResult != null)
    {
        MeshGeometry3D mesh = new MeshGeometry3D();
        mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex1]);
        mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex2]);
        mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex3]);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        GeometryModel3D marker = new GeometryModel3D(mesh, new DiffuseMaterial(Brushes.Blue));
        //...add marker to the scene...
    }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
Itai Bar-Haim
  • 1,686
  • 16
  • 40
  • we can't debug without seeing your code – Robert Levy Jul 25 '11 at 13:58
  • Well, it's a lot of code... I build the terrain using tiles of different sizes (selected using a quadtree-like mechanism, similar to the way Google Earth works). The tiles are placed in ECEF (geocentric) coordinates, so the units are meters. I'll try to make a simple demo that demonstrates it and post it later on. – Itai Bar-Haim Jul 25 '11 at 14:12
  • a small app that reproduces the problem would be helful. either there is an error in the way you do the hit testing or an error in the way you do the highlighting. if you can't post code, try rendering the ray you that you are using for the hit test to verify that it really is where you think it is – Robert Levy Jul 25 '11 at 14:24
  • I wanted to draw the ray, but the `RayMeshGeometry3DHitTestResult` object only gives me the hit point, not ray parameters (origin and direction). Any suggestions of how to get those? (using reflection, perhaps, to simulate the hit test?) – Itai Bar-Haim Jul 25 '11 at 14:36
  • ahh now the problem is clear :) WPF doesn't know what direction you are trying to hit test in... you need to give it the ray. See my answer which links to the correct HitTest method. If that helps, please click the checkmark next to it – Robert Levy Jul 25 '11 at 17:05
  • AFAIK WPF generates the (hopefully) correct ray for hit testing, so if I understand you correctly, you want me to generate this ray manually? – Itai Bar-Haim Jul 26 '11 at 07:18
  • I've managed to get and draw the ray cast from the mouse position and it seems it has nothing to do with the mouse position... How can I make sure the ray is cast correctly from the camera frustum? – Itai Bar-Haim Jul 26 '11 at 07:57
  • Does it matter that the Viewport3D control is hosted in a grid which is hosted in a UserControl which is hosted in a WinForms ElementHost presented in a floating panel provided by Syncfusion? I'm asking because I'm out of any other ideas. I already tried using Petzold's library to cast the ray manually, and I get the same results... – Itai Bar-Haim Jul 26 '11 at 08:51

3 Answers3

3

Something that caught me was that the points were in model coords. I had to transform to world coords. Here is my code that does the hit test (this will return all hits under the cursor, not just the first):

//  This will cast a ray from the point (on _viewport) along the direction that the camera is looking, and returns hits
private List<RayMeshGeometry3DHitTestResult> CastRay(Point clickPoint, IEnumerable<Visual3D> ignoreVisuals)
{
    List<RayMeshGeometry3DHitTestResult> retVal = new List<RayMeshGeometry3DHitTestResult>();

    //  This gets called every time there is a hit
    HitTestResultCallback resultCallback = delegate(HitTestResult result)
    {
        if (result is RayMeshGeometry3DHitTestResult)       //  It could also be a RayHitTestResult, which isn't as exact as RayMeshGeometry3DHitTestResult
        {
            RayMeshGeometry3DHitTestResult resultCast = (RayMeshGeometry3DHitTestResult)result;
            if (ignoreVisuals == null || !ignoreVisuals.Any(o => o == resultCast.VisualHit))
            {
                retVal.Add(resultCast);
            }
        }

        return HitTestResultBehavior.Continue;
    };

    //  Get hits against existing models
    VisualTreeHelper.HitTest(grdViewPort, null, resultCallback, new PointHitTestParameters(clickPoint));

    //  Exit Function
    return retVal;
}

And some logic that consumes a hit:

if (hit.VisualHit.Transform != null)
{
    return hit.VisualHit.Transform.Transform(hit.PointHit);
}
else
{
    return hit.PointHit;
}
Charlie
  • 81
  • 1
  • 3
1

You need to provide the ray to hit test along in order for this to work in 3d. Use the correct overload of VisualTreeHelper.HitTest which takes a Visual3D and a RayHitTestParameters: http://msdn.microsoft.com/en-us/library/ms608751.aspx

Robert Levy
  • 28,747
  • 6
  • 62
  • 94
1

Figures out it was a Normalize issue. I shouldn't have normalized the camera's look and up vectors. In the scales I'm using, the distortion is too big for the hit test to work correctly.

Itai Bar-Haim
  • 1,686
  • 16
  • 40