in shader, tutorial, Unity3D

Volumetric Rendering: Signed Distance Functions

Share Button

This tutorial explains how to create complex 3D shapes inside volumetric shaders. Signed Distance Functions (often referred as Fields) are mathematical tools used to describe geometrical shapes such as sphere, boxes and tori. Compared to traditional 3D models made out of triangles, signed distance functions provide virtually infinite resolution, and are amenable to geometric manipulation. The following animation, from formulanimation tutorial :: making a snail, shows how a snail can be created using simpler shapes:

A snail created by Signed Distance Fields.

You can find here all the other posts in this series:

Introduction

The way most modern 3D engines – such as Unity – handle geometries is by using triangles. Every objects, no matter how complex, must be composed of those primitive triangles. Despite being the de-facto standard in computer graphics, there are objects which cannot be represented with triangles. Spheres, and all other curved geometries, are impossible to tessellate with flat entities. It is indeed true that we can approximate a sphere by covering its surface with lot of small triangles, but this comes at the cost of adding more primitives to draw.

Alternative ways to represent geometries exist. One of this uses signed distance functions, which are mathematical descriptions of the objects we want to represent. When you replace the geometry of a sphere with its very equation, you have suddenly removed any approximation error from your 3D engine. You can think of signed distance fields as the SVG equivalent of triangles. You can scale up and zoom SDF geometries without ever losing detail. A sphere will always be smooth, regardless how close you are to its edges.

Signed distance functions are based on the idea that every primitive object must be represented with a function. It takes a 3D point as a parameter, and returns a value that indicates how distant that point is to the object surface.

SDF Sphere

In the first post of this series, Volumetric Rendering, we’ve seen a hit function that indicates if we are inside a sphere or not:

We can change this function so that it returns the distance from the sphere surface instead:

If sdf_spher returns a positive distance, we’re not hitting the sphere. A negative distance indicates that we are inside the sphere, while zero is reserved for the points of the space which actually make up the surface.

Union and Intersection

The concept of signed distance function was briefly introduced in Raymarching tutorial, where it guided the advancement of the camera rays into the material. There is another reason why SDFs are used. And it is because they are amenable to composition. Given the SDFs of two different spheres, how can we merge them into a single SDF?

We can think about this from the perspective of a camera rays, advancing into the material. At each step, the ray must find its closest obstacle. If there are two spheres, we should evaluate the distance from both and get the smallest. We don’t want to overshoot the sphere, so we must advance by the most conservative estimation.

This toy example can be extended to any two SDFs. Taking the minimum value between them returns another SDF which corresponds to their union:

The result can be seen in the following picture (which also features few other visual enhancements that will be discussed in the next post on Ambient Occlusion):

sdf1

With the same reasoning, it’s easy to see that taking the maximum value between two SDFs returns their intersection:

sdf2

SDF Box

Many geometries can be constructed with what we already know. If we want to push out knowledge further, we need to introduce a new SDF primitive: the half-space. As the name suggests, it is nothing more than just a primitive that occupies half of the 3D space.

The trick is to intersect six planes in order to create a box with the given size s, like shown in the animation below:

sdf3

There are more compact (yet less precise) ways to create a box, which take advantage of the symmetries around the centre:

Shape Blending

If you are familiar with the concept of alpha blending, you will probably recognise the following piece of code:

It’s purpose is to create a blending between two values, d1 and d2 , controller by a value a (from zero to one). The exact same code use to blend colours can also be used to blend shapes. For instance, the following code blends a sphere into a cube:

sdf5

Smooth Union

In a previous section we’ve seen how two SDFs can be merged together using min. If it is true that SDF union is indeed effective, it is also true that its results is rather unnatural. Working with SDFs allows for many ways in which primitives can be blended together. One of this technique, exponential smoothing (link: Smooth Minimum), has been used extensively in the original animations  of this tutorial.

When two shapes are joined using this new operator, they merge softly, creating a gentle step that removes any sharp edge. In the following animation, you can see how the spheres merges together:sdf10

SDF Algebra

As you can anticipate, all those SDF primitives and operators are part of a signed distance function algebra. Rotations, scaling, bending, twisting… all those operations can be performed with signed distance functions.

In his article title Modeling With Distance FunctionsÍñigo Quílez has worked on a vast collection of SDFs that can be used as primitive for the construction of more complex geometries. You can see some of them by clicking in the interactive ShaderToy below:

An even larger collection of primitives and operators is available in the library hg_sdf (link here) curated by the MERCURY group. Despite being written in GLSL, the functions are easily portable to Unity’s Cg/HLSL.

Conclusion

The number of transformations that can be performed with SDFs is virtually endless. This post provided just a quick introduction to the topic. If you really want to master volumetric rendering, improving your knowledge of SDFs is a good starting point.

Other Resources

📧 Stay updated

A new tutorial is released every week.

💖 Support this blog

This websites exists thanks to the contribution of patrons on Patreon. If you think these posts have either helped or inspired you, please consider supporting this blog.

Paypal
Twitter_logo

Write a Comment

Comment

  1. Wouldn’t it be more correct to call the sdf_blend function a linear interpolation also commonly referred to as lerp? Wikipedia has an example like this and I guessing it would give the same result?:

    float lerp(float v0, float v1, float t) {
    return (1 – t) * v0 + t * v1;
    }

    • Indeed! Well spotted, thank you! <3
      There's a problem with my website and I can't change the page right now unfortunately.
      Hopefully I'll remember to do it when is all done!

Webmentions

  • Volumetric Rendering - Alan Zucconi May 30, 2017

    Indeed! Well spotted, thank you! <3
    There's a problem with my website and I can't change the page right now unfortunately.
    Hopefully I'll remember to do it when is all done!

  • Issue 4 – Unity Dev Weekly May 30, 2017

    Indeed! Well spotted, thank you! <3
    There's a problem with my website and I can't change the page right now unfortunately.
    Hopefully I'll remember to do it when is all done!

  • Volumetric Rendering: Raymarching - Alan Zucconi May 30, 2017

    Indeed! Well spotted, thank you! <3
    There's a problem with my website and I can't change the page right now unfortunately.
    Hopefully I'll remember to do it when is all done!