Finally, we output a custom raster format. Given the presence of multiple coordinate systems and resolutions within a
given printer (e.g., from the motion system, linear encoders,
arrays of printhead nozzles, variably sized droplets, different
material properties), our native output is abstract enough
that it allows a printer-specific backend to perform the necessary mapping to low-level commands that take these various sources of resolution into account. Alternatively, when
targeting commercial printers that only take STL as input,
we generate a set of boundary meshes for each material
used, using a method similar to marching cubes. 13
We have designed and fabricated a variety of different
objects that highlight features of the OpenFab pipeline.
Our results were printed on an Objet Connex 500, a high-end multimaterial 3D printer that uses photopolymer phase-change inkjet technology and is capable of simultaneously
printing with two primary materials and one support material. It supports a variety of polymer-based materials that vary
in color, elasticity, and optical qualities. It takes per-material
geometry meshes as an input. The build volume of the results
is limited by the maximum number of primitives allowed by
the Objet driver software—at most about 10 million.
Our first result, as shown in Figure 5, highlights the ability to easily apply different fablets to the same base geometry. The appearance of the rhinos varies significantly, and
each uses a variety of features in OpenFab. For instance, the
left rhino uses displacement mapping in the surface phase
of the fablet to create microspikes over the rhino’s skin. The
volume phase of the fablet samples from a zebra-like texture to apply a layer of textured material near the surface.
It uses the ability to query the nearest point to both retrieve
the texture coordinate necessary to sample the texture and
determine whether to apply the textured material. The center rhino has holes carved out throughout its body by returning void in the volume phase of the fablet. We use a distance
function to separate the transparent outer shell of the rhino
from the black inner core. The right rhino achieves its look
in a similar fashion.
Our next result, the butterfly (Figure 6), highlights the use
of object priority to achieve a CSG difference-like operation.
The butterfly is placed within a transparent casing to simulate an amber fossil (the butterfly geometry has higher priority than the casing). We procedurally define volumetric
cloudiness and particles in order to increase the appearance realism of the amber.
The bunny and the teddy bear pair (Figure 7) demonstrate
the ability to reuse the same fablet across different models.
The material used to print these objects is flexible but volume preserving. The fablet introduces procedurally defined
and repeated void spaces in order to achieve a compressible,
foam-like material. This demonstrates the ability to easily
define and apply patterned materials. One could also make
the 2D or 3D pattern be texture-driven. OpenFab allows one
to build a library of such fablets similar to how material and
light libraries are built for image rendering.
The magic postcard (Figure 2) demonstrates a creative use
of texture-driven displacement mapping in its fablet (code
pipeline. Tessellated primitives are cached and reused if the
primitive straddles multiple slabs or is accessed by multiple
fablet queries. The cache has a fixed memory budget, man-
aged with a simple LRU policy.
We next evaluate the surface phase of the fablet on the
resulting tessellated mesh. We evaluate a quad at a time in
order to compute derivatives (e.g., for texture filtering) and use
OpenImageIO as our texture engine. 10
Given a processed surface, we perform solid voxelization of
its intersection with the current slab at the desired output resolution. We evaluate the volume phase of the fablet for each
covered voxel. The underlying voxel grid is optimized to store
up to 16 materials (out of a total of 64 materials that can be
defined in the fab world) to allow each voxel to be compactly
encoded in just 4 bits.
Surface distance and attribute queries are evaluated
on demand by searching the corresponding acceleration
structure. To allow fast startup, the acceleration structure
encodes base mesh primitives (expanded conservatively to
account for displacement bounds). At search time, candidate base primitives are tessellated and displaced by the surface fablet, and their microgeometry recursively searched
for the nearest point or attributes. The results of tessellation and fablet evaluation are cached in the posttessellation
surface cache, so that they are rarely recomputed. The cache
size trades off memory overhead with redundant recomputation of surface geometry accessed in multiple places.
5. 4. Output
When mixing multiple materials, we discretize the final output to a single material per voxel by applying Floyd-Steinberg
dithering9 to each slice at the same resolution as the voxelized grid. Error diffusion achieves a natural balance: if the
fablet outputs one material, the dithered output matches the
resolution of the printer, whereas if the fablet outputs multiple materials, the dithered output gracefully reduces the
resolution in order to achieve the requested material ratios.
A sliding window implementation reduces storage pressure
for large slabs and satisfies our fixed memory requirements.
Figure 4. A 2D representation of our support generation approach.
Voxels in green and yellow are part of the object being printed.
Voxels in gray are support voxels. Voxels in yellow are part of the
depth map that is generated with a high-resolution, fixed-point
rasterizer. Support voxels are generated for empty voxels if there is
a voxel in the depth map above them.