Rasterise Depth-Tested Triangles with pamtris
pamtris reads a plain-text triangle script and rasterises it into a PAM image, complete with RGB attributes and proper depth-tested overlap. The same workflow scales up to triangle strips, fans and non-colour attributes. Allow about fifteen minutes if Netpbm is already installed; nothing here needs elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the installed command
This guide uses the pamtris shipped by Netpbm 11.5.2 on the reference system. Check the binary and package on your own machine before relying on version-specific behaviour:
$ command -v pamtris
/usr/bin/pamtris
$ pamtris --version
pamtris: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
Your package version and the wording of diagnostic output may differ. The command reads its instruction script from standard input and writes one or more PAM images to standard output.
2. Choose the image contract
- Always needed:
-width,-height, and exactly one attribute declaration,-rgb,-grayscale, or-num_attribs. Width and height must each fall between 1 and 8192. -rgbis the convenient choice for an ordinary image: three attributes, theRGB_ALPHAtuple type, and a default maxval of 255.- The fourth PAM plane is opacity, managed internally by pamtris. It is not an extra value on an
attribsline. - Custom data? Use
-num_attribs=2or another value from 1 to 20, and name the tuple with-tupletypeif useful. Do not combine-tupletypewith-rgbor-grayscale.
3. Write one triangle script
Create a text file in your working directory. Each attribs line supplies the values attached to the next vertices. Coordinates use a top-left origin: x increases to the right, y increases downwards, and the z value controls depth, with smaller values nearer the viewer.
$ cat > triangle.tris <<'EOF'
attribs 255 0 0
vertex 1 1 1
attribs 0 255 0
vertex 6 1 1
attribs 0 0 255
vertex 1 6 1
print
EOF
This uses the initial triangles mode, where every three vertices make a separate triangle. A mode command is still useful when changing shape: mode strip reuses the previous two vertices for each new triangle, while mode fan keeps the first vertex and pairs it with each successive edge. Changing mode also clears the pending vertex list, so issue it before adding the next shape.
Comments start with # and run to the end of the line. Commands are case-insensitive, but full command names make scripts easier to review later. Invalid or incomplete lines are simply ignored, which can otherwise make a typo look like a missing triangle.
4. Rasterise to a new PAM file
Run the ordinary, unprivileged conversion. Redirection creates or truncates the destination, so choose a new filename while testing:
$ pamtris -width=8 -height=8 -rgb < triangle.tris > triangle.pam
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ sed -n '1,7p' triangle.pam
P7
WIDTH 8
HEIGHT 8
DEPTH 4
MAXVAL 255
TUPLTYPE RGB_ALPHA
ENDHDR
Checkpoint
The header confirms the requested dimensions, four planes (three attributes plus alpha), and the RGB tuple type. The raster data after ENDHDR is binary, so do not inspect the whole file with a terminal or text editor.
5. Verify the image without guessing
Use an installed Netpbm inspection tool if available. pamfile reads the PAM header and is safe for this output:
$ pamfile triangle.pam
triangle.pam: PAM, 8 by 8 pixels, 4 channels, maxval 255
The exact sentence can vary between Netpbm builds. Confirm the useful facts: 8 by 8 pixels, four channels and maxval 255. No pamfile? Inspect the first seven header lines as above and check the file is non-empty with test -s triangle.pam.
For a grayscale image, swap -rgb for -grayscale and give one value per attribs line. For a different sample range, pass -maxval=1023; every attribute must then be between 0 and 1023, and the output maxval changes to match.
6. Use depth and perspective deliberately
When triangles overlap, an incoming sample replaces the existing one when its interpolated depth is equal to or smaller than the stored depth. The frame starts with zero image samples and the maximum permitted depth, which makes smaller z values appear nearer, but it does not turn x and y into projected 3D coordinates on its own.
The optional fourth value on vertex is w, a perspective correction factor from 1 to 1048575. It defaults to 1 when omitted, giving ordinary linear interpolation for that triangle. If your coordinates came from a perspective projection, supply the appropriate positive integer w for every vertex of the triangle: do not invent it from z alone, calculate it as part of the projection that produced your screen coordinates.
For a quick depth check, put two overlapping triangles in the script and give the intended foreground triangle the smaller z. Keep the first result until you have inspected the replacement.
clearresets image and depth buffers, or acceptsimageordepthto clear only one.resetalso clears the image and pending vertices but deliberately leaves the depth buffer, so useclearwhen you need a genuinely fresh depth test.
7. Recover from common mistakes
- Invocation rejected? Check that width and height are present and that exactly one of the three attribute choices is supplied. RGB needs three integers after every valid
attribscommand, grayscale needs one, and values outside the current maxval are invalid. - Output empty? Check that the script reached
printand supplied three complete vertices; a mode switch discards incomplete pending vertices. - Colours attached to the wrong corners? Remember that attributes stay current until another valid
attribscommand changes them. - Redirection failed partway? Do not overwrite a known-good PAM file during diagnosis. Write to
triangle.pam.new, verify it, then replace the old file withmv triangle.pam.new triangle.pam. To undo that, restore your backup or rename the previous file back; do not delete the only copy.
Done means
- Checked
pamtrisand its Netpbm version. - Matching dimensions, attribute counts and maxval throughout the script.
- Output header confirmed the expected PAM dimensions and planes.
- Depth ordering and any
wvalues were intentional, not guessed. - Any replacement output verified before an existing file was changed.