Creating depth maps using PovRay

Written by Paul Bourke
September 2019

Norwegian translation courtesy Lars Olden.


The following is a short instructional guide to how to create depth maps using PovRay. There are various applications in stereoscopy why one might want to do this, but the motivation at the time of writing was to create depth maps for FaceBooks "3D model" images. These take an image along with an associated depth map image allowing a viewer to slightly change their view point left-right-up-down.

An example of what FaceBook accepts when a 3D model is uploaded, is illustrated below. It consists of the primary image along with a secondary image with the same name but with "_depth" appended. Obviously these are expected to match, that is, are rendered from the same view position. In this secondary image white refers to objects close to the camera and black to objects further away.


Primary image: Elephant.png

Secondary image: Elephant_depth.png

Depth maps can be generated in a number of different ways. For example, one can manually mask regions of almost constant depth and create depth maps in an image editing package. Depth maps can be created by taking a number (2 or more) photographs of an object or scene and using photogrammetric techniques derive depth maps. In the discussion here we are only going to present how to use PovRay to create depth maps of an existing 3D model. The principles are likely to be similar in other rendering packages but the terminology will be different. For example the reference below to a gradient pigment would in other packages be called a shader.

The basic features of PovRay that can be used to create depth maps is a combination of a "gradient" pigment and "colour_maps". A gradient pigment generates a number between 0 and 1 depending on the position in space of a point on the surface of the object. A colour_map is used to map that value to black-white ramp that is ultimately mapped back to depth. The following PovRay code snippet for the texture might be used.

   #declare thetexture = texture {
      pigment { 
         gradient z
         color_map {
            [0 color rgb <0,0,0> ]
            [1 color rgb <1,1,1> ]
          }
         scale <1,1,ZMAX-ZMIN>
         translate <0,0,ZMIN>
      }
      finish { ambient 1 diffuse 0 specular 0 }
   }

Notes on the above:

  • The model is assumed to be orientated such that the intended depth map is along the z axis. The camera position is similarly assumed to be along the z axis.

  • It is assumes the variables ZMIN and ZMAX have been previously declared, these map the gradient range from 0 -> 1 to zmin -> zmax.

  • The gradient pigment is periodic so the model depth needs to be contained with the bounds. This is what the the scale and translate commands are achieving.

  • The geometry of the model is assumed to be within a single union{} entity and have no existing textures applied. For example

    union { 
       object { modelpart1 }
       object { modelpart2 }
           etc
       texture { thetexture }
    }
    

Another example. This and the last are brick elephants holding up a platform on which a stupa is built, located in Sukhothai, Thailand.