surf2solid – a Tool for 3D Printing
Earlier this year Paul Kassebaum wrote a guest post on printing a 3d solid object from a thin surface. Out of that post I decided to put together the file exchange entry surf2solid, which encapsulates all of Paul’s logic into a handy little tool for preparing surfaces for 3d printing.
The main idea is that surfaces (as represented by a MATLAB patch or surface object) have no inherent thickness. Every physical real-world object has some thickness to it, so in order to bring these virtual surfaces to life as a real-world 3d object we need to add some artificial volume to it. Paul’s post outlined the approach used in surf2solid:
- Take the original thin surface
- Make a counter-surface at some other location
- Make walls joining the surface and counter-surface
Paul’s post does a great job explaining the logic behind these steps, so this post will focus on surf2solid itself and some of the ways it can be used.
surf2solid has two choices for offsetting the counter-surface - thickness and elevation. The first example below shows how to use elevation to turn a thin surface into a solid block by extrusion.
Before we begin, we need to make our simple thin surface. To keep everything in perspective, let’s aim to have our final printed 3d object be a small trinket about 4cm (40mm) in size.
n = 10; [X,Y] = meshgrid(linspace(0,40,2*n+1)); L = membrane(1,n)*30; figure, title 'Thin surface', xlabel x, ylabel y, zlabel z surf(X,Y,L,'EdgeColor','none'); colormap pink; axis image; camlight
To turn this surface into a solid block, we need to choose our horizon. You’ll notice that the lowest point of the surface is at an elevation of around -10. Let’s set our horizon just below that and form a solid block by calling surf2solid with the elevation option. If no outputs are requested, the resulting solid block will be plotted to a figure.
horizonLevel = -12; figure, xlabel x, ylabel y, zlabel z surf2solid(X,Y,L,'elevation',horizonLevel) axis image; camlight; camlight snapnow, camorbit(0,-35) snapnow, camorbit(0,-35), snapnow
If you throw in an output variable, you can capture the output of surf2solid as a MATLAB faces/vertices structure, and with a little help from stlwrite, you can make an STL file ready to send to your 3d printer.
FV_block = surf2solid(X,Y,L,'elevation',horizonLevel) stlwrite('surf2solid_block.stl', FV_block)
FV_block = faces: [1040x3 double] vertices: [685x3 double] Wrote 1 facets
Now, anyone who’s done some 3d printing before will know that many printers will charge for the amount of material in your printed object. That little block trinket we made is 31780 cubic millimeters (31.7cc), so at a going rate of $0.75/cc, printing it would set you back a cool $23.80.
So what can be done? Well, for one thing we can make our solid object more plate-like and less block-like by using the thickness option of surf2solid. One thing to keep in mind when printing thin objects is how delicate the printed object can become. With the size of our trinket, a thickness of around 3mm should be plenty to make it robust enough to at least pick out of the machine! Since we’re dealing with curved surfaces, let’s remake our original surface the same physical size, but increase n to make the curves a little smoother.
n = 50; [X,Y] = meshgrid(linspace(0,40,2*n+1)); L = membrane(1,n)*30; plateThickness = -3; % Negative to add thickness *under* our surface figure, xlabel x, ylabel y, zlabel z surf2solid(X,Y,L,'thickness',plateThickness) axis image; camlight; camlight set(findobj(gca,'Type','patch'),'EdgeColor','none') snapnow, camorbit(0,-35) snapnow, camorbit(0,-35), snapnow FV_thin = surf2solid(X,Y,L,'thickness',plateThickness)
FV_thin = faces: [40800x3 double] vertices: [21204x3 double]
Now that looks quite elegant, and the volume has been reduced to 8.5cc, so our cost of printing is now down to $6.42. Not bad, but if we’re going to be shelling out the cost of a kid’s meal for a small trinket, let’s make it worth the money and try something a little more ambitious.
One of the features Paul and I were able to add was the ability to give a variable thickness or variable elevation. This allows users to specify a thickness map matching each vertex of the original surface, rather than a constant thickness across all vertices.
% For this one we will need plenty of detail on our surface n = 400; [X,Y] = meshgrid(linspace(0,40,2*n+1)); L = membrane(1,n)*30;
And for our thickness map we can adopt an interesting ripple pattern courtesy of Steve:
km = pi; [x,y] = meshgrid(linspace(-25,50, 2*n+1)); r = hypot(x,y); rm = max(r(:)); g = sin( (km * r.^2) / (2 * rm) ); thicknessMap = 0.025*g.*abs(L) + 2.5; figure, imagesc(thicknessMap) colormap(gray), colorbar
If we run surf2solid on our surface and supply the patterned thickness map, we end up with the interesting little object you see spinning below. Furthermore, at just 3.1cc ($2.34 @ $0.75/cc) it’s well worthy of sending to the 3d printer and bringing into real-world existence.
FV_var = surf2solid(X,Y,L,'thickness',thicknessMap)
FV_var = faces: [2566400x3 double] vertices: [1289604x3 double]