Software Engineer & Media Artist

đź“· Instagram

đź’» Github

đź“ť LinkedIn

đź“¦ A program for unfolding arbitrary convex objects.

â€śUnfoldâ€ť is an implementation of the paper *Unfolding Polyhedra Method for Design of Origami Structures with Creased Folds*, as described in the book *Active Origami*. The input to the program is a 3D model (in the form of an .obj file), and the output is a rendered image of the unfolded mesh. The resulting pattern often exhibits complex structure, but the algorithm to find such an unfolding is actually quite simple. The goal of this algorithm is to find a net (i.e. an unfolding where no faces overlap) for the given *convex* polyhedron.

First, we construct a spanning tree of the faces of the input mesh (also known as the **goal mesh**). By definition, the spanning tree touches each face of the goal mesh exactly once. To construct a spanning tree, we pick an arbitrary **reference face**. We add each of the reference faceâ€™s neighbors to a queue. While the queue is not empty, we pop off the last face, add it to the spanning tree, and push each of its unvisited neighbors onto the queue. We continue in this fashion until all faces have been added to the tree. The edges of the mesh that are *not* crossed by the spanning tree form the **cut boundary**. These are the edges that must be â€ścutâ€ť in order to unfold the mesh.

The faces of the goal mesh are rotated and translated into their positions in the net via a series of transformations:

- Rotate each face to align its unit normal vector with the positive z-axis (â€śupâ€ť in our coordinate system)
- Translate and rotate each face to place one of its vertices at the origin and one of its edges along the positive x-axis
- Translate and rotate each face in the xy-plane to its final position in the net

All of these operations (including the calculation of the spanning tree) require extensive knowledge of how the vertices, edges, and faces of the goal mesh are connected to one another. To facilitate this, the mesh is stored as a half-edge data structure, which makes such adjacency queries fairly easy. There is a lot of existing literature on half-edge data structures, but essentially, each edge of the mesh stores a pair of directed *half-edges*. Every face stores a pointer to one of its half-edges. Every half-edge stores a pointer to its originating vertex, its face, the next half-edge, the previous half-edge, and its pair half-edge. Every vertex stores a pointer to one of its incident half-edges.

Determining whether *every* convex polyhedra has a net is still an unsolved problem (known as â€śDĂĽrerâ€™s conjectureâ€ť). However, many *non-convex* polyhedra do not admit a net. Practically speaking, this means that one or more pairs of faces will overlap in the unfolded net. This greatly limits the number of shapes we can â€ścorrectlyâ€ť unfold using the algorithm outlined above. For example, a torus cannot be unwrapped using this method. Nonetheless, there are still many interesting designs we can produce.

The program is meant to be used as a commandline tool. Running the executable with `--help`

will print instructions on usage:

```
Unfold 0.1
Michael Walczyk
đź“¦ A program for unfolding arbitrary convex objects.
USAGE:
unfold.exe [FLAGS] [OPTIONS] <INPUT>
ARGS:
<INPUT> Sets the input .obj file, i.e. the goal mesh
FLAGS:
-w, --wireframe Sets the draw mode to wireframe (instead of filled)
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --color_palette <COLOR_PALETTE>
Sets the color palette based on the contents of the provided .json file
-r, --resolution <PIXELS>
Sets the resolution (width and height) of the renderer [default: 1024]
```

The only required parameter is the path to the .obj file that you wish to unfold. As mentioned above, the output resolution can be set with the `-r`

flag. The canvas will always be square. By default, it is set to 1024 x 1024.

A color palette can be provided in the form of a .json file with the following schema:

```
{
"background":[
1.0,
1.0,
1.0
],
"polygons":[
[
1.0,
0.0,
0.0
],
[
0.0,
1.0,
0.0
],
[
0.0,
0.0,
1.0
]
]
}
```

In particular, `background`

specifies the background color of the canvas. `polygons`

is a list of one or more colors that will be cycled through when drawing the faces of the net. All of these values should be sub-lists with 3 elements (RGB) in the range `0..1`

. Currently, there is no way to change â€śhowâ€ť the colors are cycled through - this is something that I would like to add in the future.

An example run (with all of the options) might look like:

```
unfold path/to/goal_mesh.obj -c path/to/color_palette.json -w -r 1280
```

After some computation, the application should launch a window displaying the final net. You can take a screenshot of this window using any standard screenshot utility that is part of your operating system. Iâ€™d like to have a button or small menu to do this, but for now, Iâ€™ve left it as-is (mostly because there isnâ€™t a good way to take screenshots in `Bevy`

yet - the library Iâ€™m using for rendering).

The rendered images featured on this page come from various convex shapes Iâ€™ve modeled and manipulated in Blender. I found a lot of interesting results by sorting the faces of the .obj file before processing. For example, sorting all faces based on the y-coordinate of their centroids (Blender has built in commands for doing this). This affects the order in which faces are added to the spanning tree and thus, the look and feel of the final design.

Eventually, I would like to make the software â€śheadless,â€ť so that it simply writes an .svg file without relying on a windowing system and/or OpenGL / Vulkan. This would make it easier to send the final net to a plotter or cutting / scoring machine.

There are, of course, more advanced algorithms that are able to handle non-convex objects. I am most interested in Tomohiro Tachi and Erik Demaineâ€™s â€śtuck-foldingâ€ť method for origami design, which can handle pretty much any goal mesh. This algorithm is implemented in their software *Origamizer*.

The methodology outlined in this repo was largely based on (and inspired by) the book *Active Origami*. If you are interested in the intersection of origami, engineering, and material science, I highly recommend you check out this book! The main difference between my implementation and the one described in the book is the use of the half-edge data structure for adjacency queries.

The platonic solids in the `goal_meshes`

folder are from the following repository.

I learned how to make custom iterators in Rust from @nicalâ€™s own half-edge implementation here, which greatly simplified a lot of my code.