# And Height Maps for all…

How can there possibly be 3D modeling and visualization without height maps?

Of course, Height maps have been a staple of 3D graphics for quite some time now.  Why not extent this to 3D modeling for printing?  In this case,  I have created this nice generic RubberSheet object.  A RubberSheet is a BiParametric with a size.  So, it’s just a convenience wrapper on the BiParametric.  It assumes a basic X,Y grid, but then things get really strange.

Of course you can give it a number of steps to iterate in each of the axes, and you can give it a color sampler as well, and you can give it a VertexSampler.  What?  Yah, of course, you can just hand it a routine which will calculate the vertex at the particular grid point.  On its own, it will just lay out a flat grid, with nothing interesting on it.

This is using the standard ImageSampler.

```local colorSampler = ImageSampler.new({  Filename='firstheightmap.png',  Size = size,  Resolution = res,  MaxHeight=64, })

rubbersheet({  Size=size,  Resolution=res,  ColorSampler = colorSampler   })
```

But, what if I used the color sampler for both the color at a position, and for the x,y,z value as well? After all, it’s pretty easy to calculate the x and y, values. And the z could be calculated by taking the luminace value (gray) of the color pixel, and using that as the height. In fact the code is as simple as this:

``` function ImageSampler.GetVertex(self, u, w) local col = self:GetColor(u,w) ```
``` -- Turn it to a grayscale value local height = luminance(col) ```
``` -- Multiply by max height local x = u*self.Size[1]/self.Resolution[1] local y = w*self.Size[2]/self.Resolution[2] local z = height*self.MaxHeight local vert = {x,y,z} ```
``` return vert, {0,0,1} end ```

The ImageSampler is a functor. That is, it’s an object that has some state, and it can have simple functions called. At any rate, since I’ve implemented ‘GetVertex’, and the BiParametric object calls GetVertex if you tell it what VertexSampler to use, you can now do the following:

``` rubbersheet({ Size=size, Resolution=res, ColorSampler = colorSampler, VertexSampler = colorSampler, Thickness = -10, }) ```

As an added bonus, you can set the Thickness property, and automagically get a rubber sheet with the specified thickness, which makes it printable. This will create a rubber sheet that will follow the contours up and down. If you want a base plane, then you’d alter the lengths of the normals to be a reciprocal relationship to the height, but that’s a silly way of doing things, even though it would work.

And, there you have it. Height maps with ease. And, since it’s integral with the color Sampler, you could easily add colors based on the height value, for instance to have snow at the tops, brown dirt below that, then greenery at the bottom.