Draw smoother cones using WPF and C#

[smoother cones]

The example Draw smooth cones using WPF and C# shows how to draw some fairly smooth cones in WPF and C#. This example shows how to make even smoother cones. In the picture on the right, the cone on the left has no smoothing, the middle cone uses the previous post’s techniques, and the smoother cone on the right uses this post’s method.

In the previous example, a cone’s sides share vertices. That makes them use the same normal vector at the shared vertices so they are the same color there. That makes the cones’ sides smoother, at least at the vertices.

Unfortunately the normals farther away from the vertices are not the same so you can still see edges, although they are smoothed a bit.

One solution is to use more sides. For example, if you use 50 sides instead of 10, then the cone in the middle in the picture above looks smooth.

[smoother cones]
Another approach is to draw the cone in slices taken perpendicular to its axis. The picture on the right shows a cone with 6 sides and 2 slices. The program creates the points in the order shown and then uses them to draw the sides’ triangles.

Because the sides are smaller, the points in the sides’ triangles are closer to their vertices. That means their normals match more closely and they produce a smoother cone.

The following code shows how the new AddSmootherCone method creates the side points and uses them to make the sides for the smoother cone.

// Make the points for the sides.
Vector3D slice_axis = axis / num_slices;
double dradius = (radius2 - radius1) / num_slices;
int first_side_point = mesh.Positions.Count;
for (int slice = 0; slice <= num_slices; slice++)
    // Scale the perpendicular axes.
    double rad1 = radius1 + slice * dradius;
    double rad2 = radius1 + (slice + 1) * dradius;

    // Make the vectors have length rad1.
    Vector3D side_v1 = top_v1 * (rad1 / top_v1.Length);
    Vector3D side_v2 = top_v2 * (rad1 / top_v2.Length);

    // Add the points to the mesh.
    theta = 0;
    for (int i = 0; i < num_sides; i++)
        Point3D p1 = end_point +
            Math.Cos(theta) * side_v1 +
            Math.Sin(theta) * side_v2;
        theta += dtheta;

    // Move to the next end point, which is
    // in the middle of the slice's bottom edge.
    end_point += slice_axis;

// Make the side triangles.
pt1 = first_side_point;
for (int slice = 0; slice < num_slices; slice++)
    for (int side = 0; side < num_sides; side++)
        if (side == num_sides - 1)
            pt2 = pt1 - num_sides + 1;
            pt2 = pt1 + 1;
        int pt3 = pt1 + num_sides;
        int pt4 = pt2 + num_sides;



        // Move to the next set of points.

The code starts with a loop that makes variable slice run from 0 to num_slices. For each value of slice, the program makes a ring of points around the cone’s axis as shown in Figure 1.

The code then uses another loop to make variable slice run from 0 to num_slices - 1. For each value of slice, the program makes the triangles that make up a slice.

You’ll have to decide for your application whether you add more sides, more slices, or both to produce a smoother cone. It doesn’t matter whether you use 5 times as many sides or 5 times as many slices as the original cone, you still end up with 5 times as many triangles in the sides. (The cone on the right in the picture at the top of the post uses 4 slices and produces a pretty good result.)

Download Example   Follow me on Twitter   RSS feed   Donate

About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in algorithms, drawing, graphics, mathematics, wpf, XAML and tagged , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.