Pamtris User Manual(1) General Commands Manual Pamtris User Manual(1)
NAME
pamtris - triangle rasterizer featuring perspective-correct interpola-
tion of generic vertex attributes and depth buffering
SYNOPSIS
pamtris
-width=width
-height=height
{ -num_attribs=attributes_per_vertex [ -tupletype=tupletype ] | -rgb |
-grayscale }
[ -maxval=maxval ]
All options can be abbreviated to their shortest unique prefix. You may
use two hyphens instead of one to designate an option. You may use ei-
ther white space or an equals sign between an option name and its value.
DESCRIPTION
This program is part of Netpbm(1).
pamtris can be used to draw a great variety of 2D and 3D graphics by
composing arbitrarily complex pictures out of separate triangles, trian-
gle strips and triangle fans. The program reads instructions written in
a simple command script notation from Standard Input and outputs its re-
sults as a (potentially multi-image) PAM stream on Standard Output.
For example, the following input
mode fan
attribs 0 128 0
vertex 0 0 1
attribs 0 0 128
vertex 200 0 1
attribs 50 20 103
vertex 190 61 1
attribs 100 40 78
vertex 161 117 1
attribs 150 60 53
vertex 117 161 1
attribs 200 80 28
vertex 61 190 1
attribs 250 100 3
vertex 0 200 1
print
produces this:
Example pamtris output for FAN mode
The input file gives triangle data by setting the appropriate drawing
mode, if necessary, and then providing a list of vertices. Each vertex
is also associated with a list of up to 20 "attributes," which are inte-
ger values between 0 and a given maxval. In the most common usage, you
use pamtris to draw a visual image and a vertex has three attributes,
which are an RGB specification of a color. Such attribute lists may be
provided on a per-vertex basis.
Prior to effectively writing a PAM image to Standard Output, pamtris
first rasterizes it onto an internal frame buffer, which consists of an
"image buffer" and a "depth buffer." The image buffer consists of a se-
quence of height rows containing a sequence of width tuples. There is
one sample for each vertex attribute in every tuple plus an opacity (al-
pha) sample. Each tuple in the image buffer is also associated with an
integer depth in the depth buffer, which determines whether subsequent
drawing operations affect that particular tuple or not. This provides a
way of depth-sorting graphical objects which is adequate for many pur-
poses in 2D and 3D computer graphics. One prominent shortcoming of such
an approach to depth-sorting, however, is that it does not automatically
work with objects which are intended to appear "translucent," therefore
requiring more elaborate strategies to incorporate said objects into
pictures generated using this technique.
The opacity sample is the last sample of the tuple. pamtris manipulates
opacity internally and for any tuple it is always either 0 or the max-
val. The program does not provide the user direct control over the al-
pha image plane.
pamtris rasterizes triangles by approximating their visible area as a
collection of tuples at particular positions in the frame buffer, and to
each sample of every such tuple it assigns a value which is a perspec-
tive-correct interpolation between the values of the corresponding at-
tribute for each vertex of the triangle. Whenever a tuple within the
area of the frame buffer is produced, it is written to the corresponding
position in the frame buffer if and only if it passes a depth test.
This test works as follows: the depth value of every incoming tuple
(which is itself an interpolation between the Z-coordinates of the ver-
tices of the corresponding triangle) is compared against the value in
the corresponding position in the depth buffer. If the depth value of
the incoming tuple equals or is smaller than the depth value already
present in said position in the depth buffer, the following happens.
• Every sample i, where 0 ≤ i < num_attribs, of the tuple in
the corresponding position in the image buffer is set to equal
the value of the respective sample of the incoming tuple; and the
alpha sample (the last one) is updated to the maxval;
• The depth value in the corresponding position in the depth buffer
is updated to a depth value directly proportional to that of the
incoming tuple.
Otherwise, that particular tuple effects no change at all in the frame
buffer.
The frame buffer is initially set so that all samples in every tuple of
the image buffer contain the value 0, and all entries in the depth
buffer contain the maximum permitted depth value.
The attributes' values, and therefore the samples in the output PAM im-
ages, have no fixed interpretation ascribed to them (except for the last
image plane, which is deliberately supposed to represent tuple opacity
information); one may ascribe any suitable meaning to them, such as that
of colors, texture coordinates, surface normals, light interaction char-
acteristics, texture influence coefficients for multi-texturing, etc.
EXAMPLES
Fan Mode
The following command generates the image from the fan mode example at
the top of the ]8;;#description\DESCRIPTION]8;;\ section. If the file fan.tris contains that
code, you could process it with:
$ pamtris -height=200 -width=200 -rgb <fan.tris >fan.pam
Strip Mode
The following is an example of strip mode:
mode strip
attribs 255 0 0 # red
vertex 0 200 1
vertex 50 0 1
attribs 0 0 0 # black
vertex 100 200 1
attribs 0 205 205 # cyan
vertex 150 0 1
attribs 0 0 255 # blue
vertex 200 200 1
vertex 250 0 1
print
Save the above code in a file named strip.tris (for instance) and
process it with:
$ pamtris -height=200 -width=200 -rgb <strip.tris >strip.pam
to yield:
Example pamtris output for STRIP mode
Triangle Mode
The following is an example of triangle mode:
# yellow square
mode strip
attrib 155 155 0
vertex 50 50 100
vertex 50 200 100
vertex 200 50 100
vertex 200 200 100
# blue triangle
mode triangles
attrib 0 205 205
vertex 20 125 70
attrib 0 0 140
vertex 230 70 120 # Change "120" and see what happens
vertex 230 180 120 #
print
Save the above code in a file named pierce.tris (for instance) and
process it with:
$ pamtris -height=200 -width=200 -rgb <pierce.tris >pierce.pam
to yield:
Example pamtris output for TRIANGLES mode
Meta-programming
The pamtris command language is much too rudimentary to be used directly
for any serious drawing; you will probably want to use a general purpose
programming language to generate a temporary pamtris command file.
For example, the draw_polygon procedure in the C program below outputs
pamtris instructions to draw a regular polygon. It does this by generat-
ing a number of vertex instructions tracing around the perimeter of the
corresponding circumscribed circle. (Note: The PAM image produced by
piping the output of the below program into pamtris was subsequently
downscaled through pamscale -linear -xscale 0.25 -yscale 0.25 to achieve
an ]8;;#antialias\anti-aliased]8;;\ effect.)
Regular Polygons
/* ----------------------- *
* width = 512 *
* height = 512 *
* num_attribs = 3 *
* tupletype = RGB_ALPHA *
* ----------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14159265358979323844
void draw_polygon
(int const center_x, int const center_y, int const radius, int const sides)
{
printf("mode fan\n"
"vertex %d %d 0\n", center_x, center_y);
for(int i = 0; i <= sides; i++)
{
int const x = round(center_x + radius * cos(i*2.0*PI / sides));
int const y = round(center_y - radius * sin(i*2.0*PI / sides));
printf("vertex %d %d 0\n", x, y);
}
}
int main(void)
{
puts("attribs 0 185 80"); /* color: green */
draw_polygon(300, 210, 150, 5); /* draws pentagon */
puts("attribs 255 15 240"); /* color: magenta */
draw_polygon(150, 320, 100, 7); /* draws heptagon */
puts("!");
}
OPTIONS
In addition to the options common to all programs based on libnetpbm
(most notably -quiet, see ]8;;index.html#commonoptions\ Common Options]8;;\ ), pamtris recognizes the fol-
lowing command line options:
<dl compact="compact">
-width=width
Sets the width of the internal frame buffer and, by extension, of
the output PAM images, given in number of columns. This must be
an integer in the closed range [1, 8192].
This option is mandatory.
-height=height
This is the height of the internal frame buffer and, by exten-
sion, of the output PAM images, given in number of rows. This
must be an integer in the closed range [1, 8192].
This option is mandatory.
-num_attribs=attributes_per_vertex
This is the number of attributes per vertex. The depth of the
output PAM images equals this value plus one (to accommodate the
alpha plane). The argument must be an integer in the closed range
[1, 20].
The input instruction stream may override this with a reset com-
mand.
You must specify exactly one of -num_attribs, -rgb, and
-grayscale.
-tupletype=tupletype
This is the tuple type for the output PAM images. The argument is
a string which may be no longer than 255 characters.
The input instruction stream may override this with a reset com-
mand.
The default is a null string.
This option cannot be specified together with -rgb or
-grayscale.
-rgb This is a convenience option which simply serves as an alias for
-num_attribs=3 -tupletype=RGB_ALPHA. In other words, this option
is a quick way to specify that you are going to use pamtris to
draw RGB(_ALPHA) color images directly, and the three vertex at-
tributes are the red, green and blue levels of the color associ-
ated with the vertex, in that order.
The input instruction stream may override this with a reset com-
mand.
You must specify exactly one of -num_attribs, -rgb, and
-grayscale.
This option was new in Netpbm 10.85 (December 2018).
-grayscale
Another convenience option, similar to -rgb; except this one is
an alias for -num_attribs=1 -tupletype=GRAYSCALE_ALPHA. The one
vertex attribute is the gray level associated with the vertex.
The input instruction stream may override this with a reset com-
mand.
You must specify exactly one of -num_attribs, -rgb, and
-grayscale.
This option was new in Netpbm 10.85 (December 2018).
-maxval=maxval
Sets the maxval of the output PAM images, which is also the maxi-
mum permitted value for each vertex attribute. This must be an
integer in the closed range [1, 65535].
The default value is 255.
The input instruction stream may override this with a reset com-
mand.
INSTRUCTION CODE
The input for pamtris consists of a stream of text lines read from Stan-
dard Input.
Empty lines or lines that contain only white space characters are called
blank lines and are ignored.
When a # occurs anywhere in a line, pamtris ignores it along with every
character after it. In other words, everything from the # until the end
of the line receives the same treatment as white space.
Lines which are not blank must contain a sequence of strings, called to-
kens, separated by white space. The first such token must be one of the
commands recognized by pamtris, and all further tokens are interpreted
as the arguments for that command, if it takes any. When an insufficient
number of arguments is provided for a command, the line is considered
invalid and is given the same treatment as a blank line. The same hap-
pens when an out of range argument or one of a kind different of what is
expected is given (for example, when you give a string of letters where
a numerical value is expected), or when an unrecognized command/argument
is found. When a number of arguments greater than that required for a
particular command is provided, only the portion of the line up to the
last required argument is considered and any further tokens are ignored.
pamtris is case-insensitive. That is, mode, MODE, mODe, etc. are all
treated the same way.
The commands recognized by pamtris are:
mode
attribs
vertex
print
clear
reset
quit
You may use a minimum unique abbreviation of a command name. You may
use an exclamation mark (!) in place of the print command name and an
asterisk (*) in place of clear.
The functions of the commands are as follows.
mode { triangles | strip | fan }
This makes pamtris enter a new drawing mode. The argument is a
word which specifies the mode to change to. Instead of a full ar-
gument name, it is permissible to provide a minimum unique abbre-
viation, which has the same effect. The drawing mode will remain
the same until the next mode command is given.
This command also resets the current vertex list, which is
(re)initialized to an empty state after the command is executed.
One may add new vertices to this list through successive invoca-
tions of the vertex command (see below). You do not have to worry
about providing "too many" vertices, since the vertex list is
virtualized: pamtris maintains only the state pertaining to three
vertices at any one time. The current vertex list is initially
empty.
It is permissible to give pamtris a mode command which instructs
it to enter a drawing mode it is currently already in. One might
use this approach to reset the current vertex list without chang-
ing the current drawing mode.
Regardless of the current drawing mode, the program immediately
rasterizes a new triangle into the frame buffer as soon as you
provide the necessary vertices for it through the current vertex
list. (If you reset the vertex list before giving all the ver-
tices necessary to draw a new triangle, the program effectively
discards from the list any vertices that might have been pushed
into the vertex list up to that point without using them to draw
any new triangles.)
In the following descriptions of each drawing mode, triangles'
and vertices' indices (ordinal numbers) are 0-based.
The triangles argument instructs pamtris to enter the "TRIANGLES"
drawing mode. While in this mode, a series of separate triangles
is constructed. Every three vertices pushed into the current ver-
tex list specify a new triangle. Formally, this means that every
Nth triangle is specified by vertices 3*N, 3*N + 1, and 3*N + 2.
This is the default initial mode and is therefore not required to
be set explicitly before drawing any triangles.
The strip argument instructs pamtris to enter the "STRIP" drawing
mode. While in this mode, pamtris constructs a "triangle strip."
That is, the first three vertices pushed into the current vertex
list specify the first triangle, and every new vertex pushed af-
ter that specifies, together with the previous two, the next tri-
angle. Formally, this means that every Nth triangle is specified
by vertices N, N + 1, and N + 2.
The fan argument instructs pamtris to enter the "FAN" drawing
mode. While in this mode, a so-called "triangle fan" is con-
structed. That is, the first three vertices pushed into the cur-
rent vertex list specify the first triangle, and every new vertex
pushed after that specifies, together with the previous vertex
and the first one, the next triangle. Formally, this means that
every Nth triangle is specified by vertices 0, N + 1, and N + 2.
attribs a<sub>0 a<sub>1
a<sub>2 ... a<sub>num_attribs - 1
This updates the current attribute values list. This command
takes as arguments a sequence of num_attribs integers which rep-
resent the values of the attributes to be associated with the
next vertex. This sequence of values is the just mentioned "cur-
rent attribute values list."
Each ith argument, where 0 ≤ i < num_attribs, indicates the
value to be assigned to the ith attribute of the current at-
tribute values list. All arguments must be integer values in the
closed range [0, maxval]. If a number of arguments less than the
current value of num_attribs is given, the command is considered
invalid and is therefore ignored.
The current attribute values list remains unchanged until the
next valid attribs or reset command is given. The attribs command
allows one to change the values of each attribute individually,
while the reset command is not specifically designed for that
function, but it has the side effect of setting all values in the
current attribute values list to the maxval (see below).
All values in the current attribute values list are initially set
to the maxval.
<dt id="cmd_vertex">vertex x y z [w]
Adds a new vertex to the current vertex list (see the mode com-
mand above), assigning the values of the arguments to its respec-
tive coordinates, and the values in the current attribute values
list (see the attribs command above) to the respective entries in
the attribute list associated with the vertex.
x, y and z must be integer values in the closed range [-32767,
32767]. x and y represent, respectively, the column and row of
the tuple which corresponds to the location of the vertex. Such
values may correspond to tuples outside the limits of the frame
buffer. The origin of the coordinate system is at the top-left
tuple of the frame buffer. The X-axis goes from left to right,
and the Y-axis from top to bottom. A negative value for x indi-
cates a column that many tuples to the left of the leftmost col-
umn of the frame buffer. Likewise, a negative value for y indi-
cates a row that many tuples above the uppermost row of the frame
buffer. Observe that those coordinates correspond directly to a
particular point in the coordinate system delineated above, re-
gardless of whether you are trying to draw an image which is sup-
posed to look as if viewed "in perspective" or not; pamtris does
not "warp" the coordinates you give in any way. Therefore, if
you want to draw images in perspective, you must compute values
for x and y already projected into pamtris' coordinate system
yourself, using an external perspective projection method, prior
to giving them to the program.
The z parameter represents the Z-coordinate of the vertex, which
is used to compute depth values for tuples within the areas of
rasterized triangles. Intuitively, smaller values for z mean
"closer to the viewer," and larger ones mean "farther away from
the viewer" (but remember: as said above, the x and y coordinates
are not warped in any way, which implies that they are not af-
fected by z; neither by the next parameter, for that matter).
Optionally, you may provide a w parameter which represents a
"perspective correction factor" used to properly interpolate ver-
tex attributes across the area of the corresponding triangle.
This must be an integer value in the closed range [1, 1048575].
If you don't provide a value for it, the default value of 1 is
used (hence, if you want to nullify the effects of perspective
correction on a triangle so the output samples are computed as if
just linearly interpolated, simply do not provide a value for w
for any vertex of the triangle). If, however, you intend to draw
3D geometry in perspective, you must provide an appropriate value
for this parameter, otherwise the output images might look very
wrong. w was new in Netpbm 10.85 (December 2018).
Consider the ]8;;https://en.wikipedia.org/wiki/Viewing_frustum\ typical model]8;;\ of the so-called "viewing frustum"
used to project vertices in 3D "world space" onto a planar "image
space." If we adopt the convention that a "z-plane" means any
plane parallel to the view-plane (a.k.a. picture plane, a.k.a.
near plane), the value of w for a vertex should then be the
(smallest/euclidean/orthogonal) distance in pixels between the
projection reference point (PRP, or "eye") and the z-plane con-
taining the vertex. One way to compute this value amounts to sim-
ply taking the dot product between the 3D vector r and the 3D
unit vector n, where r is the vector which goes from the projec-
tion reference point (PRP, or "eye") to the vertex, and n is a
view-plane normal (VPN) of unit length which points away from the
PRP. In other words, this is equal to the length of the orthogo-
nal projection of r on the line "determined" by n.
(Note: For any two 3D vectors a and b, with respective real
scalar components a<sub>x, a<sub>y, a<sub>z and b<sub>x, b<sub>y,
b<sub>z, the dot product between a and b is simply
a<sub>x*b<sub>x + a<sub>y*b<sub>y + a<sub>z*b<sub>z.)
print
This writes a PAM image to Standard Output whose raster is a copy
of the current contents of the image buffer. The values of the
WIDTH and HEIGHT fields are the same as the width and height, re-
spectively, of the frame buffer, which were given on the command
line during program invocation. The MAXVAL field is equal to the
current maxval; the DEPTH field is equal to the current value of
num_attribs + 1; and the TUPLTYPE field is equal to the current
tupletype.
This command has no effect upon the current drawing state. E. g.
it does not modify the current drawing mode, the current vertex
list, etc.
One may issue an arbitrary number of print commands at different
positions in the input instruction sequence to produce a multi-
image PAM stream.
clear [ image | depth ]
Clears the frame buffer. That is, all samples in the image buffer
are once again set to 0, and all entries in the depth buffer are
once again set to the maximum permitted depth value.
Optionally, one may provide an argument to only clear either the
image buffer or the depth buffer individually, while leaving the
other intact. With the image argument, only the image buffer is
cleared; with the depth argument, only the depth buffer is
cleared. Instead of full argument names, one may provide a mini-
mum unique abbreviation, which has the same effect. The single
character z is also accepted as an alias for depth.
Like the print command, this command has no effect upon the cur-
rent drawing state either.
reset maxval num_attribs [tupletype]
This updates the current maxval and number of attributes per ver-
tex (num_attribs), resetting the <u>image</u> buffer with a new
maxval and number of samples per tuple while at it. The parameter
maxval must be an integer in the closed range [1, 65535], and
num_attribs must be an integer in the closed range [1, 20].
Optionally, after the second argument, one may provide a string
to be assigned to the current tupletype. The string goes from the
first character after the second argument which is not white
space and continues until (and including) the last character be-
fore the end of the line which is not white space. If a new tu-
pletype is not provided, or the provided string is longer than
255 characters, the empty string is assigned to the current tu-
pletype.
The side effects of running this command are
• The new image buffer is completely cleared once the command is
executed.
• All values in the current attribute values list are set to the
new maxval.
• The current vertex list is reset.
However, it does not touch the depth buffer: it is left the same
way as it was found before the command. Also the drawing mode re-
mains the same (e. g. if pamtris was in FAN mode, it will con-
tinue in that same mode, etc.).
If this command is given with an invalid value for maxval or
num_attribs, it is ignored and therefore none of the above side
effects apply, nor do the current maxval, num_attribs or tuple-
type change at all.
It is permissible to give a value for maxval and num_attribs
equal to the current maxval and num_attribs, respectively, al-
though the above side effects will still apply even in such
cases.
Since this command deals with memory allocation, it may fail to
execute successfully. If that happens, no lines of input will be
read anymore and pamtris will be terminated as if the quit com-
mand was given.
quit
This terminates pamtris. It will not read any more lines of input
after this command.
TIPS
Texturing
It is possible to apply so-called "textures" to images produced with
pamtris by using a pair of vertex attributes as texture coordinates,
then using pamchannel(1) to select the appropriate channels in the out-
put image(s), and finally processing the result through pamlookup(1),
providing the desired texture file as a "lookup table." If you are
drawing pictures in perspective, make sure to provide adequate values
for the w parameter to your vertex commands ( ]8;;#cmd_vertex\see above]8;;\ ) so that the
resulting samples in the images produced by pamtris are perspective-cor-
rect. You might want to consider using pnmtile(1) to make textures which
are inteded to be "repeated" along triangle meshes.
The animated GIF below is an example of what can be achieved using the
technique described above (Earth texture from ]8;;https://visibleearth.nasa.gov/view.php?id=73580\nasa.gov]8;;\ ).
Rotating Earth
Anti-aliased edges
pamtris performs no anti-aliasing on triangle edges by itself. However,
it is possible to obtain anti-aliased images through a "super-sampling"
approach: draw your image(s) at a size larger than the desired final
size, and then, when all postprocessing is done, downscale the final im-
age(s) to the desired size. Drawing images with twice the desired width
and height, then downscaling them to the intended size while disregard-
ing gamma (i.e. what pamscale -linear does) often produces good enough
results; but the larger the ratio "size of original im-
age" / "size of downscaled image" , the better the quality of the anti-
aliasing effect.
SEE ALSO
pampick(1) pamchannel(1) pamstack(1) pamlookup(1) pamarith(1) pam-
scale(1) pamdepth(1) pamexec(1) pam(1)
HISTORY
pamtris was new in Netpbm 10.84 (September 2018).
DOCUMENT SOURCE
This manual page was generated by the Netpbm tool 'makeman' from HTML
source. The master documentation is at
http://netpbm.sourceforge.net/doc/pamtris.html
netpbm documentation 15 April 2021 Pamtris User Manual(1)
Generated by dwww version 1.16 on Tue Dec 16 05:55:16 CET 2025.