Space filling with 3D objects using Processing

While I know I should be finishing my MakerBot time-lapse camera series, I took some time for another project to play with some Processing. The above image was rendered in Processing, in real time in just couple of minutes!

Basically, I wanted to take a simple shape, defined by an SVG path, and fill it with images of 3D objects loaded from STL files. Specifically, many wonderful MakerBot-printable objects from Thingiverse!

After some Googling around, I found out that this problem is basically a space-filling problem, similar to an excellent Processing sketch named Scattered Letters by Algirdas Rascius, but with a twist.

The basic algorithm is:

  • Load an SVG and render it to an off-screen buffer
  • Set curr_size, the size that STLs should be rendered, to max_size
  • Choose a random STL model, give it a random orientation, and render it at the current size to an off-screen buffer
  • Try several times to place this model by giving it a random x,y position and checking it for a good fit:
    • Each non-background pixel of the model's off-screen image should fit within the non-background pixels of the SVG's off-screen image.
    • Each non-background pixel of the model's off-screen image should NOT overlap with any non-background pixel of the main display.
  • If a fitting position is found, render the model to the display.
  • Otherwise, shrink curr_size by a step and choose a new model.
  • If we drop below min_size, we should stop.

You can find the code for my sketch, which I call ThingiverseCollage, on GitHub. To make it work, you’ll need to follow the installation instructions in the README to install my (very slightly) modified version of the unlekkerLib for STL loading and rendering. I modified it to allow rendering to a PGraphics object, since it originally only allowed rendering to the main PApplet.

A note on STL files: unlekkerLib only loads STL files in the binary format. It chokes dramatically on ASCII STL files, such as those exported from OpenSCAD. I was able to use Zaggo’s excellent Pleasant3D to load ASCII STLs and re-save them, which converts them to binary STLs. As a bonus, Pleasant3D also allows you to orient objects in a way that will make them look most interesting when they are rendered down to 2D in the final image.

An example M.svg, as well as several objects from Thingiverse are included with the code to get started. To use your own SVGs, I have had good luck using Inkscape to draw or import shapes, and save them as the native “Inkscape SVG” or “Plain SVG” formats. Some files might require hand-tweaking; for example, if the width and height header values are something like “100%" instead of a pixel value.

There is also some simple configuration in the sketch to allow the export of PDF files. This is nice because the resulting PDF has full vector data, making it easily rescaled to any size you wish. Unfortunately, the current PDF renderer for Processing renders each triangle of each STL model as a separate path, generating very complicated vector output, which tends to bring Inkscape to its knees. I have had some luck with importing those files, rastering them out to PNG at a high resolution (e.g. 600 dpi), and using Inkscape’s “Trace Bitmap” functionality to re-vectorize them, though this requires some cleanup by hand.

Anyway, this has been a fun little diversion for me for the last couple of days. I hope that you folks find it useful! Post your awesome pictures in the comments, here!