Displacement (DSP) map primitive

Creating a DSP object from miscellaneous images

We will use two examples to illustrate the next few sections.

1. A black and white (gray scale) image (png format):


with properties:

$ file Ex1.png
Ex1.png: PNG image, 142 x 150, 8-bit gray+alpha, non-interlaced

2. A color png file:


with properties:

$ file Ex2.png
Ex2.png: PNG image, 152 x 150, 8-bit/color RGBA, non-interlaced

Preparing your height field data

The DSP takes unsigned short (16-bit) integer data. Our various command-line data converters can help bring data in from pretty much any existing format, including image data, via various processing commands. If the data were in png image format, for example (which is basically 3-channel 8-bit integer data), the data could be prepared with a combination of 'png-pix', 'pix-bw', and 'cv'.

If you type the 'in' command, it will prompt you for each parameter individually and that should help some. For the DSP, the main parameters are: the source of the height data, the width (number of points in the X direction) and length (number of points in the Y direction) of the input data, width/length/height scaling factors, and whether to smoothly interpolate between cells (0 = do not interpolate, 1 = interpolate).

See the 'dsp_add' tool for combining two existing DSP data files into one.

A DSP primitive is an array of cells initially defined by points in the X-Y plane as positive heights from Z = 0. The DSP can then be transformed to other orientations and positions. The number of cells is (numX * numY).

The data format for the DSP primitive is network-ordered unsigned short integers (nu16). BRL-CAD has a couple of dozen tools that you can use for converting existing data into that raw format, such as the 'cv' command or the 'bw-d' and 'd-u' commands among other similar tool chains. If you use the cv command, the output format is "nus" for network unsigned shorts.

Using the two examples to convert the data to dsp format.

Example 1.

Convert it to a bw file (one pixel is one unsigned char):

$ png-bw Ex1.png > Ex1.bw

View the result:

$ bw-fb -w142 -n150 Ex1.bw

Convert it to the format required for a dsp file (nu16):

$ cv huc nu16 Ex1.bw Ex1.dsp

Example 2.

Convert it to a pix file (one pixel is defined by three unsigned chars):

$ png-pix Ex2.png > Ex2.pix

View the result:

$ pix-fb -w152 -n150 Ex2.pix

Convert it to a bw file (one pixel is one unsigned char):

$ pix-bw Ex2.pix > Ex2.bw

View the result:

$ bw-fb -w152 -n150 Ex2.bw

Convert it to the format required for a dsp file:

$ cv huc nu16 Ex2.bw Ex2.dsp

Importing DSP data into a .g file

Example 1.

In mged create a dsp object:

mged> in dsp1.s dsp f Ex1.dsp 142 150 0 ad 1 0.005
mged> r dsp1.r u dsp1.s

Example 2.

In mged create a dsp object:

mged> in dsp2.s dsp f Ex2.dsp 152 150 0 ad 1 0.005
mged> r dsp2.r u dsp2.s

Rendering your DSP

Example 1.

mged> B dsp1.r
mged> ae 270 90
mged> rt

You should see something like this:


You can play around with the scaling factors (the end pair: 1 - cell width, 0.005 - cell height) to improve the looks of the image.

But now let's invert the file so we get its negative:

$ bwmod -m-1 -a255 < Ex1.bw > Ex1n.bw

And make another dsp in the same manner as before:

$ cv huc nu16 Ex1n.bw Ex1n.dsp
$ ...

And see the results:


Example 2.

mged> B dsp2.r
mged> ae 270 90
mged> rt

You should see something like this:


Again, you could play with various parameters to get the desired look. You could also create the negative as we did with example 1 and see the results:


Creating a DSP object from manual or programmatic generation of data

A DSP object can be created manually or programmatically by creating an ASCII data file as input using the BRL-CAD utility asc2dsp to convert it directly to the DSP binary format. An easy way to create the input file for asc2dsp is to first create it row by row in natural form with the top row being the desired top row and so on in desired viewing order. Then take the finished file and filter it through the Unix utility tac which will reverse the order of the rows (lines).

For example, let's create the letter T for viewing in the X-Y plane.

$ cat t-normal.asc
1 1 1 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0

Now reverse the file:

$ tac t-normal.asc > t.asc

and see the result in perfect form for asc2dsp:

$ cat t.asc
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
1 1 1 1 1

Finally, create the dsp file:

$ asc2dsp t.asc t.sp

(The TGM creation is left as an exercise for the reader.)

A practical example

Now let's consider a more practical example and a real test of BRL-CAD. We can import topological data and produce a realistic ground surface. There are many free sources of such data, but this, for US data, seems to be the most likely:


For now, though, the format for the data is not easily found so we found another source of topological data (digital elevation models [DEM]) in SDTS format:


We selected Colorado, El Paso County, and Digital Elevation Models.

On that page we downloaded all eight 10-meter files because we were not yet sure which one we wanted. Note that you are required to have a Geo Community account for any downloads (membership is free).

We can view the SDTS with a free viewer (for Windows only) available here:


In order to examine the data in SDTS files there are two directions to take: (1) use a government supplied reader or (2) use the GDAL library mentioned above.

See these pages for details of the [ESRI] shapefile format:


Before we can create the dsp for the topo data we will have to extract the data we want and get it in shape to use. We will use the open source Geospatial Data Abstraction Library (GDAL) and its OGR subset to create a C++ program to manipulate the shapefile data. The library and documentation are available here:


We will also use the nanoflann header-only library to help transform the contour data, which is not gridded, into gridded data. That library is available here:


Our program will be made available in the BRL-CAD package.


The first thing to do is examine the data in the shapefile set. We used this reference as a guide:


and created a Perl program ("manip-shapefile.pl") to help investigate the file. The Perl program uses the Geo::ShapeFile module available from


Using the Perl program we find that the file consists of a set of 2915 PolygonZ shapes, each with one part consisting of a varying number of points, each point consisting of X, Y, and Z values.

By looking at the file "NED_DataDictionary2006.pdf" included in the shapefile set, we find that the set of polygons are topological contour lines and other data in the files define such things as units and other parameters we need to properly interpret the data.

In general, then, our first approach will be to establish an X-Y section of the set to be converted to a DSP, determine a suitable step size for gridding, and determine a suitable Z scale for the DSP.

Then, for each X-Y point in our grid, determine the closest three points in the shapefile set (with our point on or inside the triangle formed by those three points) from which to interpolate a Z value, write that XYZ to the DSP ascii file, and follow the procedures we used in the "T" case above.

Nearest neighbors

Part of the strategy is to determine the nearest "neighbors" of each of our grid points. That is defined as the "All nearest neighbors" variant ("m closest neighbors") in this discussion:



// a naive first approach for defining Z for our grid of points
for each grid point p {
  get 3 nearest neighbors of p as set n
  while (set n does not define a plane) {
    get next nearest neighbor of p
    set n[2] = next nearest neighbor
  set p.Z as the Z coordinate of intersection of vector (0, 0, 1) \
    with the plane formed by set n