3.9.11  When All Else Fails: Material Maps

We have some pretty powerful texturing tools at our disposal, but what if we want a more free form arrangement of complex textures? Well, just as image maps do for pigments, and bump maps do for normals, whole textures can be mapped using a material map, should the need arise.

Just as with image maps and bump maps, we need a source image in bitmapped format which will be called by POV-Ray to serve as the map of where the individual textures will go, but this time, we need to specify what texture will be associated with which palette index. To make such an image, we can use a paint program which allows us to select colors by their palette index number (the actual color is irrelevant, since it is only a map to tell POV-Ray what texture will go at that location). Now, if we have the complete package that comes with POV-Ray, we have in our include files an image called povmap.gif which is a bitmapped image that uses only the first four palette indices to create a bordered square with the words "Persistence of Vision" in it. This will do just fine as a sample map for the following example. Using our same include files, the camera and light source, we enter the following object.

  plane {
    -z, 0
    texture {
      material_map {
        gif "povmap.gif"
        interpolate 2
        once
        texture { PinkAlabaster }          // the inner border
        texture { pigment { DMFDarkOak } } // outer border
        texture { Gold_Metal }             // lettering
        texture { Chrome_Metal }           // the window panel
      }
      translate <-0.5, -0.5, 0>
      scale 5
    }
  }

The position of the light source and the lack of foreground objects to be reflected do not show these textures off to their best advantage. But at least we can see how the process works. The textures have simply been placed according to the location of pixels of a particular palette index. By using the once keyword (to keep it from tiling), and translating and scaling our map to match the camera we have been using, we get to see the whole thing laid out for us.

Of course, that is just with palette mapped image formats, such as GIF and certain flavors of PNG. Material maps can also use non-paletted formats, such as the TGA files that POV-Ray itself outputs. That leads to an interesting consequence: We can use POV-Ray to produce source maps for POV-Ray! Before we wrap up with some of the limitations of special textures, let's do one more thing with material maps, to show how POV-Ray can make its own source maps.

To begin with, if using a non-paletted image, POV-Ray looks at the 8 bit red component of the pixel's color (which will be a value from 0 to 255) to determine which texture from the list to use. So to create a source map, we need to control very precisely what the red value of a given pixel will be. We can do this by

  1. Using an rgb statement to choose our color such as rgb <N/255,0,0>, where "N" is the red value we want to assign that pigment, and then...
  2. Use no light sources and apply a finish of finish { ambient 1 } to all objects, to ensure that highlighting and shadowing will not interfere.

Confused? Alright, here is an example, which will generate a map very much like povmap.gif which we used earlier, except in TGA file format. We notice that we have given the pigments blue and green components too. POV-Ray will ignore that in our final map, so this is really for us humans, whose unaided eyes cannot tell the difference between red variances of 0 to 4/255ths. Without those blue and green variances, our map would look to our eyes like a solid black screen. That may be a great way to send secret messages using POV-Ray (plug it into a material map to decode) but it is no use if we want to see what our source map looks like to make sure we have what we expected to.

We create the following code, name it povmap.pov, then render it. This will create an output file called povmap.tga (povmap.bmp on Windows systems).

  camera {
    orthographic
    up <0, 5, 0>
    right <5, 0, 0>
    location <0, 0, -25>
    look_at <0, 0, 0>
  }
  plane {
    -z, 0
    pigment { rgb <1/255, 0, 0.5> }
    finish { ambient 1 }
  }
  box {
    <-2.3, -1.8, -0.2>, <2.3, 1.8, -0.2>
    pigment { rgb <0/255, 0, 1> }
    finish { ambient 1 }
  }
  box {
    <-1.95, -1.3, -0.4>, <1.95, 1.3, -0.3>
    pigment { rgb <2/255, 0.5, 0.5> }
    finish { ambient 1 }
  }
  text {
    ttf "crystal.ttf", "The vision", 0.1, 0
    scale <0.7, 1, 1>
    translate <-1.8, 0.25, -0.5>
    pigment { rgb <3/255, 1, 1> }
    finish { ambient 1 }
  }
  text {
    ttf "crystal.ttf", "Persists!", 0.1, 0
    scale <0.7, 1, 1>
    translate <-1.5, -1, -0.5>
    pigment { rgb <3/255, 1, 1> }
    finish { ambient 1 }
  }

All we have to do is modify our last material map example by changing the material map from GIF to TGA and modifying the filename. When we render using the new map, the result is extremely similar to the palette mapped GIF we used before, except that we didn't have to use an external paint program to generate our source: POV-Ray did it all!