I did a quick search of the Makie docs and here on discourse and I didn’t see any hits discussing this. Is it possible to export 3D plots to .stl files for 3D printing?
Yes, and .OBJ files too. I prefer .OBJ files for the following reasons described in this essay.
A widely used file format for 3D objects is STL (short for STereoLithography) created by 3D Systems. In essence, the STL file format is a list of triangle definitions with each triangle defined by
- the triangle’s three vertices,
- a unit vector normal to the triangle’s face, and
- the triangle’s color.
Quite often, the triangle’s unit vector is set to zero because it can be calculated from the three vertices. Also quite often, the triangle’s color is set to zero because the model doesn’t require a color definition for each triangle. Therefore, quite often 14 of the triangle definition’s 50 bytes (or 28%) are set to zero. Another inefficiency of the STL file format is the duplicate vertices: given that most vertices in a typical 3D mesh appear in more than one triangle, a more memory efficient approach to storing a typical 3D mesh would be to define each vertex just once and then refer to it with an index.
That is what the OBJ file format does. Created by Wavefront Technologies, the OBJ file format is a list of vertex definitions followed by a list of triangle definitions, with each triangle defining its three vertices by three indices into the vertex list. Although it is not the most popular file format for 3D objects, the OBJ file format is the 3D object file format used in this essay due to its efficiency and its simple hierarchy:
- the vertex list is a list of three dimensional coordinates of each vertex,
- the triangle list is a list of index triples into the vertex list,
- (in the application) the 3D component list is a list of references into the triangle list, and
- (again in the application) the 3D object is a list of references into the 3D component list.
Conveniently, the same OBJ 3D files can be plotted by Julia and Makie and sliced and printed by AnkerMake.
The same essay (3D Modeling for the Blind) also lists some Julia code that reads and writes .STL and .OBJ files.
Thanks for the info. I didn’t see an example of writing a .stl file in that post and the .obj file looks like it’s being written manually (line by line). I was wondering if there was a more automated/batteries-included solution. For example, if I produce the following plot (from beautiful.makie.org):
using GLMakie
GLMakie.activate!()
u = LinRange(0.8, 6, 50)
v = LinRange(0, 2π, 50)
X1 = [u for u in u, v in v]
Y1 = [(1/u) * cos(v) for u in u, v in v]
Z1 = [(1/u) * sin(v) for u in u, v in v]
fig = Figure(resolution=(1200, 800))
ax = LScene(fig[1, 1], show_axis=false)
surface!(ax, -X1, -Y1, Z1;
shading=true, ambient=Vec3f(0.65, 0.65, 0.65),
backlight=1.0f0, color=sqrt.(X1 .^ 2 .+ Y1 .^ 2 .+ Z1 .^ 2),
colormap=Reverse(:bone_1), transparency=true,
)
Is there an easy way to save this as a .STL file?
using FileIO, MeshIO, GLMakie
mesh(m; ...)
save("m.obj", m)
of course in this case the thing you are saving is actually the mesh object and not the plotting of the mesh. You will need to transform that surface into a mesh object I suppose for that case above.
It wasn’t that long ago when I unboxed my AnkerMake M5 printers and I’m still a novice at 3D printing, but I think there are a few notable differences between saving a mesh file that can be plotted with Makie and saving a mesh file that can be sliced and printed with PrusaSlicer or AnkerMake Slice(Beta).
- The surface faces must all be triangles for the slicers.
- On a given horizontal slice, each encountered mesh (e.g., traveling on a scan line) toggles between filling and not filling. So if you want your print to be hollow as it appears in your plot, you would need to specify a mesh at an outer radius AND a mesh at an inner radius. Otherwise the printed object would be solid.
- Overhangs at an azimuth angle greater than 45 degrees may require printed supports. In your plot, it looks like the overhang at the bottom ring is more than 45 degrees.
Concerning writing a .STL file that can be printed, the link to the Wikipedia page about the .STL file format gives a helpful outline but is missing details about the 80 byte file header. Perhaps you can use a binary editor to open a .STL file that correctly prints on your 3D printer and just use the same 80 byte header in the .STL file you write. That worked for me when I was testing the different file formats. As shown below, the .STL header I use is mostly zeros.
Hi! Any workaround? I am just starting to work with 3D printing and I am a bit stucked.
I have a 3D body I need to print, but all I have is a set of coordinates where the body is and where it isn’t in the space.
Here a general view
And here a close up to a 2D slice
If you are using Meshes.jl, take a look at GeoIO.jl, which is the module responsible for loading/saving meshes into all sorts of formats:
I wanted to do the same today and found a simple way to convert an isosurface into a 3d-printable file.
# first evaluate a function on a grid whose level sets give the surface you want
using LinearAlgebra
using StaticArrays
# for example, a sphere
dat = [sqrt(sum(dot(v,v))) - 1 for v in Iterators.map(SVector, Iterators.product(range(-2, 2, length=40), range(-2, 2, length=40), range(-2, 2, length=40)))]
# see a plot of the isosurface
using GLMakie
GLMakie.volume(dat; algorithm=:iso, isovalue=0.0, isorange=0.1, colormap=cgrad([:teal, :teal], 10))
# generate a mesh of the isosurface
using Meshing
alg = MarchingCubes(iso=0.0)
points, faces = isosurface(dat, alg)
# plot the mesh
using GeometryBasics
mesh(points, map(v -> GeometryBasics.TriangleFace(v...), faces);color=:yellow, shading=true)
# export the mesh
msh = GeometryBasics.Mesh(GeometryBasics.Point.(points), SimplexFace.(faces))
using GeoIO
save("msh.obj", msh)
On my print, I started with my geometry and file, uploaded it to the 3d printing software to “slice” it, and sent the job to the printer. This is what the whole process looked like:
Unfortunately, my (yellow) mesh plot didn’t have any shading, but the final product came out looking nice