Super Shaping with Lua

There are literally thousands of ways to produce 3D models for printing and other purposes.  Over the past year, I have chosen to focus on the non-visual forms of creation, particularly using OpenScad as my primary design tool.  As I’ve written before, OpenScad is a great design tool for a programmer like me who’s not particularly familiar with the more visual design tools.

Time and again though, I’m looking for ways to enhance my experiences with OpenScad.  There’s always that extra feature I want, or speed enhancements, or whatever.  A while back, I started exploring using Lua as a programming language to do my modeling.  Lua is a nice little embeddable scripting language.  It’s been around for quite a long time, and is fairly fast.  It’s simple in concepts, if a bit quirky in some of its syntax.  It’s not that I want to dump OpenScad in favor of Lua, but what I do want to do is enhance my modeling toolchain to improve in some areas, without resorting to creating big monolithic be-all end-all applications.

Recently, I have produced some models derived from the SuperFormula.  I used OpenScad alone to produce the results, and they can be found here: OpenScad SuperShape

One of the limitations of OpenScad is that there are no dynamic arrays.  That is, you can not append to an array.  Ideally what you would do in order to construct a mesh based object is figure out all the vertices, and then construct a Polyhedron object using those vertices.

Since I can not construct an array dynamically, I have to resort to actually creating the polyhedron piecemeal.  I have gotten this technique to work.  In the case of the SuperShape, it looks like the following:
polyhedron(
points = [pa,pb,pc,pd],
triangles = [
[0,3,2], // pa, pd, pc
[0, 2, 1] // pa, pc, pb
]);

There is an outer loop where I am calculating the vertices (pa, pb, pc, pd), and then generating a piece of the polyhedron based on those vertices.  I am responsible for stitching it together in such a way that I end up with a nicely 2-manifold object.

This technique works fairly well, and I don’t know of another/better way of doing it in OpenScad.

The disadvantage of this technique is that if you want to perform CSG operations within the same script, you will have problems.  Although in my mind, what I am doing is creating one big giant solid object, what is in fact happening is that I am creating a whole bunch of little tiny objects, and they so happen to stitch together nicely enough to form a solid.

When it comes time to perform CSG operations, I do NOT in fact have one big solid object, but a bunch of little tiny objects that must be individually compared and dealt with by the CSG system.  Even for a fairly small number of objects (thousands), this can take an extremely long time (10s of minutes, even hours).

A possible solution here is to use some other program, which does have dynamic arrays, to generate the polygon, and then just output the result to OpenScad.

Enter Lua.  I could use Python, Ruby, JavaScript, or pick your favorite programming language.  It doesn’t really matter, the process will remain the same.

The setup is like this.  First of all, you have your program generate some OpenScad file.  In the case of SuperShape, I have rewritten the code in Lua.  The core of the routine looks like the following:


local pa = mesh:addvertex(pocart(1/r0,1/r1,theta1,phi1))
local pb = mesh:addvertex(pocart(1/r2, 1/r1, theta2, phi1))
local pc = mesh:addvertex(pocart(1/r2, 1/r3, theta2, phi2))
local pd = mesh:addvertex(pocart(1/r0, 1/r3, theta1, phi2))

mesh:addface({pa, pd, pc})
mesh:addface({pa, pc, pb})
What’s going on here is that I have a PolyMesh object, the ‘mesh’ instance here.  You can fill a PolyMesh objects with vertices, then you can come back later and tell it how the vertices relate to create faces, and edges, if you like.

Separately, I have created a simple function that will turn a PolyMesh into an OpenScad polyhedron() module call.

function PolyMesh_print(f, mesh)
f:write("polyhedron(points= [\n");
for i,pt in ipairs(mesh:Vertices()) do
vec3_print(f, pt);
f:write(",\n");
end
f:write("],\n");

f:write(“triangles=[\n”);
for i,v in ipairs(mesh:Faces()) do
print_face_tuple(f, v)
f:write(‘,\n’)
end
f:write(“]);\n”);
end

The end result is that I can write the following, to generate a supershape and get OpenScad output:

PolyMesh_print(f,RenderSuperShape(
supershape(7, 0.2, 1.7, 1.7, 1, 1),
supershape(7, 0.2, 1.7, 1.7, 1, 1),
64,
128))

By default, I just write to a file with the name “test_supershape.scad”.  On the OpenScad side of thing, I simply open this file, press F5, and I get a visualization of the thing.  This will give me a quick visualization using OpenCSG.  To go further, you can press F6, and get an actual compile through CGAL.  In this particular case, it took 1 minute, 16 seconds to do the render and display.

This is a very fast result.  While I am typing this post, I am still waiting for the plain OpenScad method to complete its render, and it has already been 20 minutes!

UPDATE:  The render for the method using OpenScad directly finally completed:  It took 18 hours 50 minutes!  That’s a few orders of magnitude slower than the technique where you have a complete polyhedron to play with.  Same number of vertices, exact same geometry and topology.  Just piecewise vs having a single polyhedron call.

 

To go one step further, I don’t just want one static polyhedron, and be done.  I want to play with it, changing parameters, messing around with things.  I want to change something on the Lua side, and see the render instantly on the OpenScad side.  There is a feature in OpenScad that allows you to deal with this.

In the OpenScad window, under the “Design” menu, the first item is “Automatic Reload and Compile”.  If you check this item, whenever the file changes on disk, it will be automatically realoaded and compiled.  What that means is, you can go ahead and make your changes in the Lua side, and regenerate the file, and it will just automatically re-render.  The best way to take advantage of this is to have both your Lua editor open, and the OpenScad file, and just make changes, save, and view the results on the OpenScad side.

This design flow works well for me.  Many of the objects that I am creating are ultimately just meshes.  All of the geometry, height map, and other random stuff, that’s not heavy on the CSG side, can be created simply, and OpenScad used as the viewing tool.

Similarly, OpenScad serves as the CSG tool, providing the connection to CGAL for me.  Of course I could bind to CGAL from Lua directly.  But, OpenScad is already doing this part for me, so I don’t have to bother with it.

Another benefit of generating the Polyhedron completely like this is I can actually perform CSG operations within script, without taking a ton of time.  No warnings about too many vertices, or CSG operations being disabled.  That’s really nice.

Doing this CGAL operation, from within OpenScad, using my previous method of piecewise construction of the polyhedron, would literally take all day to perform, and might not actually complete.

And one last thing.  As long as I’ve gotten things into that PolyMesh object on the Lua side, I can directly generate .stl files.  Since I’m not actually doing any CSG operations, I don’t need the help of CGAL.  So, in the end, OpenScad is a nice visualizer for this particular tool chain.  It’s a viable way of working for me, and it makes things go a lot faster.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s