Signed Distance Functions: Modeling in Math

What if instead of defining a mesh as a series of vertices and edges in a 3D space, you could describe it as a single function? The easiest function would return the signed distance to the closest point (negative meaning you were inside the object). That’s precisely what a signed distance function (SDF) is. A signed distance field (also SDF) is just a voxel grid where the SDF is sampled at each point on the grid. First, we’ll discuss SDFs in 2D and then jump to 3D.

SDFs in 2D

A signed distance function in 2D is more straightforward to reason about so we’ll cover it first. Additionally, it is helpful for font rendering in specific scenarios. [Vassilis] of [Render Diagrams] has a beautiful demo on two-dimensional SDFs that covers the basics. The naive technique for rendering is to create a grid and calculate the distance at each point in the grid. If the distance is greater than the size of the grid cell, the pixel is not colored in. Negative values mean the pixel is colored in as the center of the pixel is inside the shape. By increasing the size of the grid, you can get better approximations of the actual shape of the SDF. So, why use this over a more traditional vector approach? The advantage is that the shape is represented by a single formula calculated at many points. Most modern computers are extraordinarily good at calculating the same thing thousands of times with slightly different parameters, often using the GPU. GLyphy is an SDF-based text renderer that uses OpenGL ES2 as a shader, as discussed at Linux conf in 2014. Freetype even merged an SDF renderer written by [Anuj Verma] back in 2020.

How are SDFs defined? A circle is easy to define as it is the length of the vector to the center minus the circle’s radius. Rectangles are a little more complicated, but [Ronja] has a handy walkthrough of the concept. It’s easy to determine the distance from an infinite line with some thickness (T) centered at (0,0). Just take the absolute value of the distance to one of the edges or abs(T – sample_point.x). It would be naive to calculate those two values and then take the length of the resulting vector. This generates incorrect distances inside the shape. Instead, the correct way to do this is to calculate the inside and outside distance and cap them so they don’t flip signs. The rectangle below shows lines representing the distance (red being negative).

Rotations, scaling, and transformations modify the sample point before it is evaluated. This allows some remarkable properties, such as mirroring or repeating infinitely. Merging multiple objects is as easy as taking the minimum between them. An intersection is just a max operation. You can smoothly interpolate between objects by linearly interpolating the distances. Bevels, chamfers, and smooth blending are all trivial with some math. Deriving each of these equations is an exercise left to the reader, but existing videos and articles walk you through each primitive.

We even have an example SDF on Shadertoy of the Hackaday logo for you to play with (click on it to see a visualization of the distance). Shadertoy is a playground that allows you to play around with GLSL shader code right in your browser.

SDFs in 3D

Rather than triangles, meshes, or voxels, a 3D SDF is a mathematically defined shape with potentially infinite detail. [Inigo Quilez] created a fantastic video that details how to paint a beautiful landscape scene with SDFs, and it is well worth the watch. He also has a Shadertoy you can play with right in your browser.

Of course, SDFs have some downsides compared to traditional meshes. Deforming them is tricky and the deformations must be integrated into the actual model. That is, without something like a non-linear deformation space, as this paper talks about. Another drawback is that the performance can be significantly slower than rasterization. Large SDFs like selfie girl by [Inigo] (seen below) are quite taxing even on large desktop-class GPUs.

Code-wise, rendering the image is simpler than you think, with a ray marcher fitting in just 135b of WebGL. Some handy libraries, such as hg_sdf, make adding SDFs to the demo scene easier. Since their code is minuscule, they are a common technique, as we recently covered. [SimonDev] has an excellent video that explains Ray Marching in a clear, concise manner.

CAD is another common avenue for SDF as it can easily generate complex chamfered and organic shapes that would be hard to describe in a constraint-based system. In particular, booleans become much simpler in an SDF space as compared to a mesh space. Several projects on GitHub offer a great developer experience with bells and whistles included. Generally, the marching cubes algorithm with an octree is used to turn the SDF into actual mesh geometry for 3D printing.

Conclusion

Signed Distance Functions are incredibly powerful and quite accessible. You can start playing around with them in your browser, C++ libraries, python, or in a few different CAD packages. Why not bring them into a space-constrained environment or start creating some art without modeling anything?



Signed Distance Functions: Modeling in Math
Source: Manila Flash Report

Post a Comment

0 Comments