DFAO and Soft Shadows based on SDF - A Unity Production

2019-08-09

screenshot preview [Link to this project] on Github.

This project is using an offline SDF baker (SDFr), and maintaining global distance field at runtime. Current shadowing functions run at about 120 fps, while I guess it would be more suitable for generally static scenes, which means that you’d better to use it for things that seldom change or move, to avoid efficiency problems.

There are some slides with videos to illustrate the project better (in the Github repository), originally it was not written in English and was converted by google translate, please check it you’d like to.

Please notice that within this article, I used some screenshots from my slides, because my website is not ready to display formulars, I hope this doesn’t bother you much.

What’s it about?

The work of this project is originally completed through an internship at NetEase Inc., it includes:

  • Research on the use of S DistanceField Field
  • Unity implementation: Offline baking of local SDF smodels
  • Unity implementation: Global SDF for real-time maintenance, global Distance Field
  • Unity implementation: GDF-based real-time soft shadows and ambient occlusion rendering

What is a signed distance field (SDF)?

Distance field is a form of mapping in 2D/3D space: from any point p, mapping to the distance d to the nearest boundary (2D) or plane (3D) in the space.

Distance fields have many categories, SDF is one of them, which is characterized by distinguishing the inner and outer properties of the grid, with a positive distance outside the grid and a negative one inside.

SDF’s application in 2D space is mainly font rendering, proposed by Valve in 2006.

Applications of SDF in 3D space include collision detection, model representation and deformation, ambient occlusion, soft shadowing, etc.

Content of this project

SDFBaker

sdfbaker

SDFBaker.cs a monobehavior script that can be attached on objects with mesh or children containing mesh

SDFBaker bakes out SDF data for the collection of all mesh under this object, ant it is offline, and the baking results are written to disk for reuse and instantiation of object.

class

The class diagram of SDFBaker is shown above, the basic interfaces are already provided, and SDF baker is just one implementation of possible baker on this framework. You could even use it to implement bakers for something else.

Global Distance Field

gdf

The implementation of runtime Global Distance Field (GDF) is in DistanceFieldAtlas.cs

  • At the beginning of execution, detect all objects in the scene that include SDF components, cache their SDF instances, and weight them according to the SDF file name used;

  • The equal width (actually the exact same dimension) SDF Texture is injected into a separate Texture3D and passed to the GPU end. If there are 3 x 64^3 SDFs in the scene, the texture size is 64x64x192. This operation only needs to be performed once. GDF is a low-resolution Custom Render Texture size of 64^3 or 128^3

  • Maintain spatial transformation information for all objects with SDF, detect the activation of objects per frame (GameObject.activeSelf) and whether the transformation occurs (Transform.isChange), and, if so, trigger update events

  • The GDF update is done within a Shader, and updating the GDF requires the transfer of the StructuredBuffer <VolumeData>, i.e. spatial transformation and AABB information for all objects in the scene, as well as a number of parameters.

Update of GDF

GDFUpdate.shader:

  • For each fragment, get its uv coordinates and transform to the world coordinates of the GDF carnouspresses it represents (replace with p below)

Define the VolumeData structure at the shader end in GDFTexturing.hlsl:

gdfshader

The pseudo-code to update the GDF texture:

for (vd in StructuredBuffer<VolumeData>) :
    if ( InsideAABB(p, vd) ):
        dist = SampleAtlas(textureAtlas, vd.TextureIndex, p)
    else:
        dist, dist2* = GlobalAABBPlus(textureAtlas, vd.TextureIndex, p)
    minDist = min(dist, minDist)

Illustration for distance calculation

img

However, distances got from this method is not accurate, and if you know how ray-marching works, you would realize that sometimes a ray would jump over a surface if your are not using a confidentially small step size. To fix this problem, I introduced a method to get a rather confident value for the step of ray-marching:

img img

Images and Videos of the results

screenshot preview screenshot result

The videos are, againly, stored in the slides.

Thanks for reading.

2019-08-09