Draw a 3D surface overlaid with a grid using WPF and C#

3D surface overlaid with a grid

This example shows how to use C# code and XAML to draw a 3D surface overlaid with a grid. The example Apply textures to triangles using WPF and C# shows how to apply textures to triangles. This example simply uses that technique to apply a bitmap holding a large grid to a surface.

At the class level, the program uses the following code to define scale factors that map a point’s X and Z coordinates to the range 0.0 – 1.0.

private const double texture_xscale = (xmax - xmin);
private const double texture_zscale = (zmax - zmin);

The following code shows how the program adds a new point to the 3D model.

// A dictionary to hold points for fast lookup.
private Dictionary<Point3D, int> PointDictionary =
    new Dictionary<Point3D, int>();

// If the point already exists, return its index.
// Otherwise create the point and return its new index.
private int AddPoint(Point3DCollection points,
    PointCollection texture_coords, Point3D point)
{
    // If the point is in the point dictionary,
    // return its saved index.
    if (PointDictionary.ContainsKey(point))
        return PointDictionary[point];

    // We didn't find the point. Create it.
    points.Add(point);
    PointDictionary.Add(point, points.Count - 1);

    // Set the point's texture coordinates.
    texture_coords.Add(
        new Point(
            (point.X - xmin) * texture_xscale,
            (point.Z - zmin) * texture_zscale));

    // Return the new point's index.
    return points.Count - 1;
}

As in earlier examples, the code defines a dictionary to hold Points so it can look them up quickly. The AddPoint method looks up a point and adds it if it doesn’t already exists. It then uses the point’s X and Z coordinates to map the point to the 0.0 – 1.0 range of the U-V coordinates used by the object’s texture. In other words, points with the smallest X/Z coordinates are mapped to U/V coordinates near (0, 0) and points with the largest X/Z coordinates are mapped to U/V coordinates near (1, 1).

After it creates the triangles, the program uses the following code to create its material.

// Make the surface's material using an image brush.
ImageBrush grid_brush = new ImageBrush();
grid_brush.ImageSource =
    new BitmapImage(new Uri("Grid.png", UriKind.Relative));
DiffuseMaterial grid_material = new DiffuseMaterial(grid_brush);

The file Grid.png simply contains a 513×513 pixel grid. Alternatively you could create the grid in code. A third approach would be to use partial derivatives to figure out where the lines should be drawn and then use skinny rectangles or boxes to draw them on top of the surface. (A later post will explain how to draw skinny boxes.) That would be a LOT more work, however.

I know these examples omit a huge amount of detail. They build on each other so you’ve seen the key points in earlier posts. The details are also fairly long so, to save space, I’m not going to include them in every post. Download the example to see how the whole thing works.


Download Example   Follow me on Twitter   RSS feed   Donate




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

11 Responses to Draw a 3D surface overlaid with a grid using WPF and C#

  1. Draw a 3D surface overlaid with a shaded altitude map using WPF and C#

    The example Draw a 3D surface overlaid with a grid using WPF and C# explains how to overlay an image on a three-dimensional surface. This example does something similar. Instead of simply using an existing image containing a grid, however, it generates an image that is shaded to show the surface’s height. The following CreateAltitudeMap method generates the texture bitmap. // Create the altitude map texture bitmap. private void CreateAltitudeMap() { // Calculate the function’s value over the area. const int xwidth = 512; …

  2. Dietrich Hadler says:

    Hi,
    I downloaded the previous surface code examples and they are simply amazing!
    Is the code for this example also available?

    Best regards,

    Dietrich

  3. RodStephens says:

    Sorry. I looked at the post and I think my ISP’s conversion to WordPress messed up the download links. I’ve rebuilt this example (and the other one you commented on). I’ll try to do the others in this series soon.

  4. Phan Sang says:

    Hi Rods, I had compared function “Add Triangle” in this program and the others one in your program like : tetrahedron, icosahedron. They are quite different, could you explain which one is the better one, Thank you.

    • RodStephens says:

      There are three basic ways you can add a triangle. First, you can add a new point for each vertex. If you do that, then triangles that share edges don’t share vertices so the graphics software does not smooth the edge between them. That’s what you would do for a shape with non-smooth edges such as a cube or tetrahedron.

      Second, you can reuse existing points for the vertices of new triangles. In that case the graphics software smooths the edges between the triangles that share vertices. This is what you would do for a smooth shape like a sphere, torus, or smooth surface.

      Third, you can include texture coordinates in either of the first two options. That makes the graphics software use the texture to color pixels. The example on this page uses methods 2 and 3 so it produces a smooth textured surface.

      I suspect the examples you’re studying have those kinds of differences.

  5. Phan Sang says:

    Even more, when I change the value of texture_xscale and texture_yscale. The size of the surface remain the same regardless of the value it take( I even set one of them or both to 1 million). I don’t understand why. I think I have asked too much, I hope you don’t mind, ha ha :D.

    • RodStephens says:

      Texture coordinates should always be between 0.0 and 1.0. They don’t have anything to do with the shape of the surface itself, they just determine what parts of the texture image are mapped to the triangles’ vertices.

      If you don’t use the whole texture image for some vertices, WPF also seems to try to be helpful by scaling the texture coordinate. That can mess up where the coordinates are mapped so you get an incorrect result. (I don’t know what Microsoft was thinking with this one.) To prevent that, make sure you use the full width and height of the texture image. In other words, some vertex should have texture X = 0, another should have texture X = 1, and the same for the Y coordinates.

      My guess is when you set the texture coordinates to something really big, WPF scaled the coordinates to fit on the 0.0 – 1.0 scale.

  6. Ezra Sidran says:

    I’m trying to do something similar. I have a .bmp that is a height map and another .bmp that is an image that I want to use for the surface texture. How can I do this? I’ve done it in XNA but I need to do it, again, in WPF.

Leave a Reply

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