smish.dev
triply_periodic_surfaces

Triply-Periodic Surfaces

When 3D printing, we often want to partially fill the interior of a part with some structure to provide reinforcement. This page describes a few implicit functions f(x,y,z) that can be used to generate infill patterns through surfaces defined by the points that satisfy f(x,y,z)=0:

all_surfaces

All of these functions are periodic in x, y, and z, so they can be tiled to cover any region of space.

Note: the vec3 type in the C++ code snippets below is just a 3-element array of floats, like glm::vec3 or std::array<float,3>.

 


Gyroid

f(x,y,z)=sin(x)cos(y)+sin(y)cos(z)+sin(z)cos(x)

SchwarzP

f(x,y,z)=cos(x)+cos(y)+cos(z)

SchwarzD

f(x,y,z)=sin(x)sin(y)sin(z)+sin(x)cos(y)cos(z)+cos(x)sin(y)cos(z)+cos(x)cos(y)sin(z)

Neovius

f(x,y,z)=3(cos(x)+cos(y)+cos(z))+4cos(x)cos(y)cos(z)

SchoenIWP

f(x,y,z)=2(cos(x)cos(y)+cos(y)cos(z)+cos(z)cos(x))(cos(2x)+cos(2y)+cos(2z))

FischerKochS

f(x,y,z)=cos(2x)sin(y)cos(z)+cos(2y)sin(z)cos(x)+cos(2z)sin(x)cos(y)

FischerKochY

f(x,y,z)=2cos(x)cos(y)cos(z)+(sin(x)sin(y)+sin(y)sin(z)+sin(z)sin(x))

FischerKochCP

f(x,y,z)=cos(x)+cos(y)+cos(z)+4cos(x)cos(y)cos(z)

Normalization for Thin Surfaces

A complication shows up when trying to use these function definitions as infill patterns-- how do we create a structure with a given thickness?

For signed-distance functions, this is easy: if the surface is defined by s(x,y,z)=0, then |s(x,y,z)|t2<0 defines a region of thickness t centered on that surface:

sdf_thickness

The same idea (sort of) works for implicit functions too, except that:

Although both of these issues can be solved by numerically solving the Eikonal equation to turn the implicit functions into SDFs, that gets pretty expensive and messy. Instead, we'll observe that since the surface is defined by f(x,y,z)=0, multiplying our definition of f by some nonzero number wouldn't affect the surface. With that in mind, we can pick a scaling factor such that small values of the parameter t once again take on the physical interpretation of thickness-- at least, in an average sense.

One way to pick such a scaling factor is to notice that the gradient of a signed distance function has unit norm: ||s||=1, but our implicit functions don't. So, if we can scale the function such that ||f||1 near the surface, then it will behave more like a SDF with respect to the thickness parameter, t. So, we start by discretizing the surface into a bunch of triangles, and then sampling points from each triangle to calculate ||f|| near the surface:

surface_histogram

From there, dividing through by the mean of those values will make the scaled version of f have ||f||1 near the surface like we wanted. Normalization values calculated this way are tabulated below:

FunctionScaling
Gyroid1.53346
SchwarzP1.33861
SchwarzD1.49765
Neovius2.8835
SchoenIWP4.3453
FischerKochS1.80497
FischerKochY2.25957
FischerKochCP2.44358

Mathematica Notebook

Here's the mathematica notebook used to perform the normalization analyses and render the images in this document: triply_periodic_minimal_surfaces.nb