The Z-Buffer Device

Device Keywords Accepted by the Z Device:

CLOSE, DECOMPOSED, GET_DECOMPOSED, GET_GRAPHICS_FUNCTION, GET_PIXEL_DEPTH, GET_WRITE_MASK, SET_CHARACTER_SIZE, SET_COLORS, SET_FONT, SET_GRAPHICS_FUNCTION, SET_PIXEL_DEPTH, SET_RESOLUTION, SET_WRITE_MASK, Z_BUFFERING

The IDL Z-buffer device is a pseudo device that draws 2-D or 3-D graphics in a buffer contained in memory. This driver implements the classic Z buffer algorithm for hidden surface removal. Although primarily used for 3-D graphics, the Z-buffer driver can be used to create 2-D objects in a frame buffer in memory. The resolution (dimensions) of this device can be set by the user.

All of the IDL plotting and graphics routines work with the Z-buffer device driver. In addition, the POLYFILL procedure has a few keyword parameters, allowing Gouraud shading and warping images over 3-D polygons, that are only effective when used with the Z-buffer.

When used for 3-D graphics, two buffers are present: an 8-bit-deep or 24-bit deep frame buffer that contains the picture; and a 16-bit-deep Z-buffer of the same resolution, containing the z-value of the visible surface of each pixel. The Z-buffer is initialized to the depth at the back of the viewing volume. When objects are drawn, the z-value of each pixel is compared with the value at the same location in the Z-buffer, and if the z-value is greater (closer to the viewer), the new pixel is written in the frame buffer and the Z-buffer is updated with the new z-value.

The frame buffer is 8 bits deep by default, but can be configured to be 24 bits deep using the SET_PIXEL_DEPTH keyword to the DEVICE routine. In 8-bit mode, the low-order 8 bits of any color specification are written to the 8-bit frame buffer. In 24-bit mode, the behavior depends on the value of the DECOMPOSED keyword to the DEVICE routine. When DECOMPOSED=1 (the default), the 24-bit color specification is stored in the 24-bit frame buffer, providing TrueColor functionality. When DECOMPOSED=0, the lower 8 bits of the color specification are used to index the current color lookup table to obtain 3-channel color information to store in the 24-bit frame buffer. Use the SET_COLORS keyword to the DEVICE routine to limit the maximum color index value used in this process.

The Z-buffer device is a "pseudo device" in that drawing commands update buffers in memory rather than sending commands to a physical device or file. The TVRD function reads the contents of either buffer to an IDL array. This array may then be further processed, written to a file, or output to a raster-based graphics output device.

The Z-buffer driver can be used for 2-D graphics by disabling the depth computations.

To use the Z-buffer as the current graphics device, issue the IDL command:

SET_PLOT, 'Z' 

Once the Z-buffer driver is enabled, the DEVICE procedure is used to control its actions, as described below.

Use the statement:

HELP, /DEVICE 

to view the current state of the Z-buffer driver and the amount of memory used for the buffers.

Reading and Writing Buffers

The contents of both frame and depth buffers are directly accessed by the TV (or TVSCL) and TVRD routines via the CHANNEL keyword. Access the buffers as follows, depending on the device pixel depth:

8-bit Pixel Depth

When the Z buffer device pixel depth is 8 bits (the default), the assignments for the CHANNEL keyword are:

CHANNEL
Buffer
Data Type

0

8-bit Frame Buffer (color indices)

byte

1

16-bit Depth Buffer

signed integer

Use CHANNEL=1 and set the WORDS keyword when reading or writing the depth buffer in 8-bit mode.

The Z buffer device ignores the TRUE keyword in 8-bit mode.

24-bit Pixel Depth

When the device pixel depth is 24 bits, the assignments for the CHANNEL keyword are:

CHANNEL
Buffer
Data Type

0

3 8-bit Frame Buffer channels (Red, Green, Blue)

byte

1

8-bit Frame Buffer (Red channel)

byte

2

8-bit Frame Buffer (Green channel)

byte

3

8-bit Frame Buffer (Blue channel)

byte

4

16-bit Depth Buffer

signed integer

Use CHANNEL=4 and set the WORDS keyword when reading or writing the depth buffer in 24-bit mode.

In 24-bit mode, the interleave is controlled by the value of the TRUE keyword:

TRUE
Interleave

0

None (see below)

1

Pixel

2

Row

3

Band

If TRUE=0:

Using the Z Buffer

The normal procedure is to set the graphics device to "Z", draw the objects, read the frame buffer, and then select another graphics device and write the image. For example, to create an image with the Z-buffer driver and then display it on an X-Window display:

; Select Z-buffer device: 
SET_PLOT,'Z' 
; Write objects to the frame buffer using normal graphics  
; routines, e.g. PLOT, SURFACE, POLYFILL 
... ... ... 
; Read back the entire frame buffer: 
a=TVRD() 
; Select X Windows: 
SET_PLOT,'X' 
; Display the contents of the frame buffer: 
TV, a 

To read the depth values in the Z-buffer, use the command:

a = TVRD(CHANNEL=1, /WORDS) 

To write the depth values, use the command:

TV, a, /WORDS, CHANNEL=1 

The TV, TVSCL, and TVRD routines write or read pixels directly to a rectangular area of the designated buffer without affecting the other buffer.

Z-Axis Scaling

The values in the depth buffer are short integers, scaled from -32765 to +32765, corresponding to normalized Z-coordinate values of 0.0 to 1.0, where 1.0 represents the plane closest to the viewer.

Polyfill Procedure

The Z device draws patterns specified via the PATTERN keyword to the POLYFILL procedure using one of two methods:

The following POLYFILL keywords are active only with the Z-buffer device: IMAGE_COORDINATES, IMAGE_INTERPOLATE, and TRANSPARENT. These parameters allow images, specified via the PATTERN keyword, to be warped over 2-D and 3-D polygons. The values of the IMAGE_INTERPOLATE and TRANSPARENT keywords apply only when IMAGE_COORDINATES are specified.

The Z device converts all image data specified with the PATTERN keyword to BYTE.

Image data can be supplied in either an [m x n] array (a single-channel image), or as an [3 x m x n] array (a three-channel image). Table A-20 describes how different types of image data interact with the device pixel depth and the DECOMPOSED setting of the device.

Table A-20: Z Device Pixel Depth vs. Depth of POLYFILL Pattern

Z Device
Pixel Depth
Number of PATTERN Channels
DECOMPOSED Setting
Resulting Pattern Image
8
1
n/a

Grayscale

8
3
n/a

Grayscale, created from first (red) channel

24
1
0

Color table applied

24
1
1

Single image channel replicated to grayscale

24
3
n/a

True color

The IMAGE_COORDINATES keyword specifies a [2 x n] array containing the image space coordinates that correspond to each of the n vertices of the polygon.

The IMAGE_INTERPOLATE keyword indicates that bilinear interpolation is to be used, rather than the default nearest neighbor sampling.

Pixels less than the value of the TRANSPARENT keyword are not drawn, simulating transparency. The TRANSPARENT keyword is a byte value. A three-channel image pixel is not drawn only when all three components are less than the TRANSPARENT value. If performing color table lookup (Z device pixel depth is 24, PATTERN is one channel, and DECOMPOSED=0), the pixel is not drawn if the single-channel pixel is less than the transparent value.

For Gouraud shading of polygons, the COLOR keyword can contain an array specifying the color index for each polygon vertex.

Examples Using the Z-Buffer

This example forms a Bessel function, draws its shaded surface and overlays its contour, using the Z-buffer as shown in the following figure. The final output is directed to a PostScript file.

; Store the original display device
oldDevice = !D.NAME

; Select the Z-buffer:
SET_PLOT, 'Z'
n = 50 ; Size of array for Bessel

; Make the Bessel function:
a = BESELJ(SHIFT(DIST(n), n/2, n/2)/2, 0)

; Draw the surface, label axes in black, background in white:
SHADE_SURF, a, /SAVE, COLOR=1, BACKGROUND=255
nlev = 8 ; Number of contour levels

; Make the Contour at normalized Z=.6:
CONTOUR, a, /OVERPLOT, ZVALUE=.6, /T3D, $
LEVELS=FINDGEN(nlev)*1.5/nlev-.5, COLOR=1

; Read image:
b=TVRD()

; Select PostScript output:
SET_PLOT, 'PS'

; Select a file name for the output file
DEVICE, FILENAME = DIALOG_PICKFILE(FILE='zbuffer-1.ps')

; Output the image:
TV, b

; Close the new PostScript file:
DEVICE, /CLOSE

; Select the original device:
SET_PLOT, oldDevice

Figure A-7: Combined Shaded Surface and Contour Plot

devices6.gif

If we use a 24-bit Z device, we can prepare a true color image that can then be displayed on a 24-bit display. (Here, we assume that the display monitor is a TrueColor device):

; Store the original display device
oldDevice = !D.NAME
DEVICE, GET_DECOMPOSED=oldDecomposed

; Select the Z-buffer:
SET_PLOT, 'Z'
DEVICE, SET_PIXEL_DEPTH=24, DECOMPOSED=0
LOADCT, 5
n = 50 ; Size of array for Bessel

; Make the Bessel function:
a = BESELJ(SHIFT(DIST(n), n/2, n/2)/2, 0)

; Draw the surface, label axes in black, background in white:
SHADE_SURF, a, /SAVE, COLOR=1, BACKGROUND=255
nlev = 8 ; Number of contour levels

; Make the Contour at normalized Z=.6:
CONTOUR, a, /OVERPLOT, ZVALUE=.6, /T3D, $
   LEVELS=FINDGEN(nlev)*1.5/nlev-.5, COLOR=1

; Read image:
b=TVRD(/TRUE)

; Select the original device and set window size:
SET_PLOT, oldDevice
DEVICE, DECOMPOSED=oldDecomposed
WINDOW, XSIZE=(SIZE(b))[2], YSIZE=(SIZE(b))[3]

; Output the image:
TV, b, /TRUE

Using the 24-bit Z device, we can also modify the example to use full 24-bit color specifications, rather than picking colors from a color table:

; Store the original display device
oldDevice = !D.NAME
DEVICE, GET_DECOMPOSED=oldDecomposed

SET_PLOT, 'Z'
DEVICE, SET_PIXEL_DEPTH=24, DECOMPOSED=1
n = 50 ; Size of array for Bessel

; Make the Bessel function:
a = BESELJ(SHIFT(DIST(n), n/2, n/2)/2, 0)

; Draw the surface and axes in red, background in purple:
SHADE_SURF, a, /SAVE, COLOR='000000d2'x, BACKGROUND='00ff80c0'x
nlev = 8 ; Number of contour levels

; Make the Contour at normalized Z=.6:
CONTOUR, a, /OVERPLOT, ZVALUE=.6, /T3D, $
   LEVELS=FINDGEN(nlev)*1.5/nlev-.5, $
   C_COLORS=['00ffff00'x, '0000ffff'x, '00ff00ff'x]

; Read image:
b=TVRD(/TRUE)

; Select original output and set window size:
SET_PLOT, oldDevice
DEVICE, DECOMPOSED=oldDecomposed
WINDOW, XSIZE=(SIZE(b))[2], YSIZE=(SIZE(b))[3]

; Output the image:
TV, b, /TRUE

The 24-bit Z buffer device is useful for creating a TrueColor image from an 8-bit display. The following example creates (and then displays) an image file from a display window that uses an 8-bit color lookup table.

; Read an image file containing elevation data
file = FILEPATH('worldelv.dat', $
   SUBDIRECTORY = ['examples', 'data'])
image = READ_BINARY(file, DATA_DIMS = [360, 360])

; Store the original display device
oldDevice = !D.NAME
DEVICE, GET_DECOMPOSED=oldDecomposed

; Write the image to the 24-bit Z buffer device, using a
; color lookup table. Note that we must set the DECOMPOSED
; keyword to zero to create the color image.
SET_PLOT, 'Z'
ERASE
DEVICE, SET_PIXEL_DEPTH=24
DEVICE, SET_RESOLUTION=[360,360]
DEVICE, DECOMPOSED=0
LOADCT, 33
TVLCT, 255,255,255, !D.TABLE_SIZE - 1
TVSCL, image

; Read the image array back from the Z buffer device
; and write it to a TIFF file.
new_image = TVRD(/TRUE)
new_file = GETENV('IDL_TMPDIR')+'world.tif'
WRITE_TIFF, new_file, new_image

; Change back to the original device
SET_PLOT, oldDevice
DEVICE, DECOMPOSED=oldDecomposed

; Read in the TIFF file and display it.
tif_image = READ_TIFF(new_file)
WINDOW, XSIZE=360, YSIZE=360, TITLE='Image read from TIFF file'
TV, tif_image, /TRUE

The following example warps an image to a cube as shown in the figure below. The lower two quadrants of the image are warped to the front two faces of the cube. The upper-right quadrant is warped to the top face of the cube.

; Read an image from a JPEG file and resize it to
; 100 by 100 pixels.
READ_JPEG, FILEPATH('rose.jpg', $
   SUBDIRECTORY=['examples', 'data']), rose
nx = 100
ny = 100
rose = CONGRID(rose, 3, nx, ny)

; Store the original display device
oldDevice = !D.NAME

; Change to the Z buffer device
SET_PLOT, 'Z'
DEVICE, SET_PIXEL_DEPTH=24, SET_RESOLUTION=[400,400]

; Make a greenish background:
ERASE, '80ff80'x

; Establish 3-D scaling as (0,1) cube:
SCALE3, XRANGE=[0,1], YRANGE=[0,1], ZRANGE=[0,1]

; Define vertices of cube. Vertices 0-3 are bottom, 4-7 are top:
verts = [[0,0,0], [1,0,0], [1,1,0], [0,1,0], $
   [0,0,1], [1,0,1], [1,1,1], [0,1,1]]

; Fill lower left face:
POLYFILL, verts[*, [3,0,4,7]], /T3D, PATTERN=rose, $
   IMAGE_COORD=[[0,0], [nx/2,0], [nx/2,ny/2], [0,ny/2]]

; Fill lower right face:
POLYFILL, verts[*, [0,1,5,4]], /T3D, PATTERN=rose, $
   IMAGE_COORD=[[nx/2,0], [nx-1,0], $
   [nx-1,ny/2], [nx/2,ny/2]]

; Fill top face:
POLYFILL, verts[*, [4,5,6,7]], /T3D, PATTERN=rose, $
   IMAGE_COORD = [[nx/2,ny/2], [nx-1,ny/2], $
   [nx-1,ny-1], [nx/2,ny-1]]

; Draw edges of cube in black:
PLOTS, verts[*, [0,4]], /T3D, COLOR=0

; Edges of top face:
PLOTS, verts[*, [4,5,6,7,4]], /T3D, COLOR=0
img = TVRD(/TRUE)

; Change back to the original device and display:
SET_PLOT, oldDevice
WINDOW, XSIZE=400, YSIZE=400
TV, img, /TRUE

Figure A-8: TrueColor Image Warped to a Cube Using the Z-Buffer

devices7.gif