Draw triangle vertex normals on a 3D model using WPF and C#

example

This example is somewhat similar to Draw surface normals on a 3D model using WPF and XAML except it draws vertex normals in addition to surface normals, a wireframe, and the surface itself. It uses the following code to create a MeshGeometry3D object holding segments showing vertex normals for an existing MeshGeometry3D object.

// Return a MeshGeometry3D representing the mesh's triangle normals.
public static MeshGeometry3D ToVertexNormals(
    this MeshGeometry3D mesh, double length, double thickness)
{
    // Copy existing vertex normals.
    Vector3D[] vertex_normals = new Vector3D[mesh.Positions.Count];
    for (int i = 0; i < mesh.Normals.Count; i++)
        vertex_normals[i] = mesh.Normals[i];

    // Calculate missing vetex normals.
    for (int vertex = mesh.Normals.Count;
        vertex < mesh.Positions.Count; vertex++)
    {
        Vector3D total_vector = new Vector3D(0, 0, 0);
        int num_triangles = 0;

        // Find the triangles that contain this vertex.
        for (int triangle = 0; triangle <
            mesh.TriangleIndices.Count; triangle += 3)
        {
            // See if this triangle contains the vertex.
            int vertex1 = mesh.TriangleIndices[triangle];
            int vertex2 = mesh.TriangleIndices[triangle + 1];
            int vertex3 = mesh.TriangleIndices[triangle + 2];
            if ((vertex1 == vertex) ||
                (vertex2 == vertex) ||
                (vertex3 == vertex))
            {
                // This triangle contains this vertex.
                // Calculate its surface normal.
                Vector3D normal = FindTriangleNormal(
                    mesh.Positions[vertex1],
                    mesh.Positions[vertex2],
                    mesh.Positions[vertex3]);

                // Add the new normal to the total.
                total_vector = new Vector3D(
                    total_vector.X + normal.X,
                    total_vector.Y + normal.Y,
                    total_vector.Z + normal.Z);
                num_triangles++;
            }
        }

        // Set the vertex's normal.
        if (num_triangles > 0)
            vertex_normals[vertex] = new Vector3D(
                total_vector.X / num_triangles,
                total_vector.Y / num_triangles,
                total_vector.Z / num_triangles);
    }

    // Make a mesh to hold the normals.
    MeshGeometry3D normals = new MeshGeometry3D();

    // Convert the normal vectors into segments.
    for (int i = 0; i < mesh.Positions.Count; i++)
    {
        // Set the normal vector's length.
        vertex_normals[i] = ScaleVector(vertex_normals[i], length);

        // Find the other end point.
        Point3D endpoint = mesh.Positions[i] + vertex_normals[i];

        // Create the segment.
        AddSegment(normals, mesh.Positions[i], endpoint, thickness);
    }

    return normals;
}

This method first creates an array of Vector3D objects to hold normals for all of the mesh’s points. Then, if the mesh includes normal data, it copies that data into the array.

If the mesh is missing normal data for any of its points, the program loops through those points. For each such point, the code loops through the TriangleIndices array to see which triangles use that point. The code calls the FindTriangleNormal method (described in the earlier post) to get all of the triangles’ normals and averages them to create the vertex normal.

(This method of averaging triangle surface normals gives each triangle that contains the vertex the same weight. For example, if one side of the vertex has one big triangle and the other side has lots of little triangles, the little triangles will tend to overpower the big one. You could change that behavior, but I’m not sure how you would want to do that. I don’t know what algorithm WPF uses if you don’t specify vertex normals yourself.)

After it has calculated all of the vertex normals, the program loops through the normals and adds them to a MeshGeometry3D object for display.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in algorithms, drawing, geometry, graphics, mathematics, wpf, XAML and tagged , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

2 Responses to Draw triangle vertex normals on a 3D model using WPF and C#

  1. Ramesh says:

    please include the xaml code too.

Leave a Reply

Your email address will not be published. Required fields are marked *