Saturday, August 6, 2011

Hit Testing in 3D Graphics

I did some playing around with Hit Testing using the Visual Tree Helper class. Here are a few things that I learned:

  • The viewport mouse-down event does not fire unless the cursor is over a displayed triangle in the viewport. I am thinking it would be possible to place a large surface at end of the field of view opposite from the camera. There is no reason this could not be almost transparent.
  • It is easy to get the vertices of the triangle that was hit.
  • It is easy to get the point on the surface where the hit occurred.
  • You can the endpoints of a line along the cursor using the following code:

LineRange range;
ViewportInfo.Point2DtoPoint3D(_viewport, ptMouse, out range);

In the viewport mouse-down event, I put the following code:

base.OnMouseLeftButtonDown(args);
Point ptMouse = args.GetPosition(_viewport);

VisualTreeHelper.HitTest(_viewport, null, HitTestDown, new PointHitTestParameters(ptMouse));

I then created the HitTestDown call-back routine:

HitTestResultBehavior HitTestDown(HitTestResult result) {

    RayMeshGeometry3DHitTestResult resultMesh = result as RayMeshGeometry3DHitTestResult;
    ModVis3D vis = resultMesh.VisualHit as ModVis3D;
    string nl = Environment.NewLine;
    int Vertex1 = resultMesh.VertexIndex1;
    int Vertex2 = resultMesh.VertexIndex2;
    int Vertex3 = resultMesh.VertexIndex3;

    string sResult = vis.Generator.Name + nl;
    sResult += Vertex1 + " " + Vertex2 + " " + Vertex3 + nl;
    sResult += resultMesh.VertexWeight1 + " " + resultMesh.VertexWeight2 + " " + resultMesh.VertexWeight3 + nl;
    sResult += resultMesh.PointHit.X + " " + resultMesh.PointHit.Y + " " + resultMesh.PointHit.Z + nl;
    Model3D mod = resultMesh.ModelHit;
    if (mod is Model3DGroup) {
        sResult += "mod is Model3DGroup" + nl;
    } else {
        GeometryModel3D model = mod as GeometryModel3D;
        MeshGeometry3D mesh = model.Geometry as MeshGeometry3D;
        sResult += "Vertex1: ";
        sResult += mesh.Positions[Vertex1].X.ToString() + " ";
        sResult += mesh.Positions[Vertex1].Y.ToString() + " ";
        sResult += mesh.Positions[Vertex1].Z.ToString() + " ";
        sResult += nl;
        sResult += "Vertex2: ";
        sResult += mesh.Positions[Vertex2].X.ToString() + " ";
        sResult += mesh.Positions[Vertex2].Y.ToString() + " ";
        sResult += mesh.Positions[Vertex2].Z.ToString() + " ";
        sResult += nl;
        sResult += "Vertex3: ";
        sResult += mesh.Positions[Vertex3].X.ToString() + " ";
        sResult += mesh.Positions[Vertex3].Y.ToString() + " ";
        sResult += mesh.Positions[Vertex3].Z.ToString() + " ";
        sResult += nl;
       
    }
    SWF.MessageBox.Show(sResult);
    return HitTestResultBehavior.Stop;
}

No comments:

Post a Comment