A friend of mine approached me about helping him with a costume for a wizard character in a live-action roleplaying game. We decided that a cloak was a good place to start, and I immediately wanted to incorporate some technomancer aspects—for example, a 3D-printed cloak clasp. I’ve been getting back into the swing of working with Rhino after upgrading my OS to be able to use the free beta version of Rhino for Mac (which has stabilized a lot since the last time I looked into it), so that seemed like a good place to start. Rhino is very popular among architectural designers and Grasshopper, the visual UI for scripting Rhino processes, has grown an extensive community since last I checked, but what really appealed to me was using a plugin to do some scripting in Python. I’d have access to all of the Rhino commands in a language I already knew how to work with. Using it is relatively straightforward if you’re already familiar with Rhino’s commands+arguments workflow, which is translated very literally into the Python module.
I love the work that Nervous System does with subdivided surfaces, and I’d just overheard half of a lecture on Voronoi diagrams, so I was thinking about Voronoi filigrees. I pictured something kind of spiky and airy, with a bit of blobbiness around the intersections of lines, appropriately organic yet shiny for a fantasy-medieval technomancer.
I didn’t have enough time alotted to make it totally generative, but I wanted two scripts to make the task easier: one for generating Voronoi diagrams out of points, and one to turn lines into 3D shapes. The former turned out to be a matter of grabbing an existing library and interpreting its data. The latter uses Rhino’s “pipe” command, which takes a curve (in the 3D modeling sense: any series of connected points, including line segments) and a series of radii at points along the curve and generates a pinched cylinder. I also merged spheres at the ends of the pipes so that each strut is a self-contained blobby unit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
which turns this: into this: The full code (including things like interpreting between the rhinoscriptsyntax and voronoi modules’ similar but non-identical ideas about how points should be represented) is on Github.
Unfortunately, the timeline for this project is somewhat compressed and the deadline to get the print done in time for the LARP snuck by us, so I’m putting the design of the clasp on hold to get the rest of the cloak out the door in time with a placeholder clasp.
Python/Rhino things to watch out for
Boolean operations (in the 3D modeling sense: adding and subtracting shapes from each other) are just as prone to mysterious failure as they are in plain Rhino. I suspect I’m running into problems relating to coplanar surfaces, which Rhino’s boolean solver hates. I’m “fixing” this by only automating the booleans in each strut (pipe plus spheres) and merging the whole structure by hand. This was never going to be a fully autonomous process, so no big problem there, but it’s something I’ll want to fiddle with in the future.
Another thing is that it’s possible that one source of mysterious failures I saw was an incompatibility between Python’s floats and Rhino’s ideas about acceptable tolerances. I incorporated this:
1 2 3 4 5 6 7
and run decimate() on the data I get back from voronoi.py instead of telling Rhino to plot arbitrarily precise lines. It seems to help, but it’s possible that this is pure superstition.
More vexingly, there are some problems with the Rhino for Mac Python plugin itself. A lesser one is that the documentation is not always very detailed, and Rhino’s own functions fail silently; for example, it took me a pretty long time to realize that all of the strings offered up to GetBoolean() needed to be purely alphanumeric, with no spaces, because it would display the prompt properly but just not show the expected tickyboxes. A bigger problem is that the output of
Update: My forum post has yielded a link to a post which answers my caching question: Python isn’t reloading imported modules unless the code explicitly calls
reload(module). Good to know!