## Implicit Representations & Signed Distances in the Metafold API

Unlike discrete, tessellated surface representations—e.g. triangle meshes, the Metafold geometry kernel represents shapes **implicitly** through **shape functions**. These implicit shape functions give us the **signed distance** to the **surface** (or zero level set) of the shape from a given point position in $\mathbb{R}^3$. By querying the surface distance at a sufficient number of varied point positions (often referred to as “**sampling** the shape”), we are able to build an approximate picture of the implicit shape. The detail of this “picture” depends on the number of points we use to sample the shape, and the strategy we use to vary the point positions. The higher the shape’s complexity, the more points are needed to capture the surface in sufficient detail, and vice versa.

*complete*representation of the shape, but of course each sample requires a certain amount of memory, and we don’t have an infinite amount of memory. We will revisit the inverse relationship between precision and memory multiple times in this document. The bottom line is: sample density will vary depending on your use case. For example, sampling an implicit shape for stereolithography (SLA) or digital light processing (DLP) 3D printing will demand enough points to meet the specific manufacturing tolerances of the printer involved, i.e. number of slices x number of pixels per-slice supported by the UV projector; whereas generating a triangle mesh from the implicit shape can likely get away with much fewer points.

Sampling implicit shapes using a **3D grid** of **uniformly distributed points** is a naive, yet effective strategy to capture detail without knowing more about the shape upfront. As implicit shapes have no bounding box per se, choosing an appropriate position and size for the uniform grid can be challenging. If the shape is as simple as an ellipsoid, then grid placement is trivial provided you know the ellipsoid center and size. If the shape is a lattice however, our implementation repeats the lattice unit cell infinitely in all directions in $\mathbb{R}^3$, so there is no obvious grid placement!

It’s a little like shining a torch into a dark room full of objects, without first scanning the room once with the light, it’s hard to know where to focus the torch light to get more detail on the object you care about.

Things get more complex when the shape function is composed of multiple shapes, and even more tricky when coordinate transforms are involved. We therefore leave grid placement up to the designer of the shape function, who is the most informed to make this decision.

We *could* store results using a sparse data structure, but this turns out to have little-to-no (or worse) space savings for highly complex microstructures, e.g. a design space filled with a dense lattice, which are a key benefit of using implicit shapes. The current binary output format is also incredibly fast and simple to read and write, allowing our customers to get going quickly without any special decoders needed.
We could do better, but we could also do *much worse* in terms of storage.
**Tip:** You can use the `export_vdb`

job to output sparse level set data in OpenVDB format if desired.

With signed distances sampled onto a grid (referred to as a **volume**), we can render the shape by further sampling the grid values. Depending on how far apart the grid points are, some interpolation of grid values may be required to approximate distances between the available points. We can also use this method to sample volumes in other shape functions (TODO: Link). Interpolating grid values is computationally cheap and fast, this is particularly convenient for us as it allows us to cache the results of comparatively slow and expensive shape functions, e.g. sampling a triangle mesh (TODO: Link), and use the cached volume in subsequent shape functions—trading precision for processing speed.