本篇将介绍如何在体积着色器中创建复杂的三维模型。

有向距离函数(通常被称为场)是用来描述球形,盒子及环面几何形状的数学工具。和传统的由三角形组成的3D模型相比,有向距离函数提供了几乎无限的分辨率,并且适合进行几何体操作。下面的动画展示了如何使用更简单的形状去创建一个蜗牛:

泰课在线

介绍
 

大多数现代的3D引擎(如Unity)都使用三角形来处理几何体。每一个物体,无论多复杂,都是由原始的三角形所组成。尽管这在计算机图形学中是实际标准,但不是所有物体都能用三角形表示。球形以及其它曲面几何形状就无法被细分为平面实体。虽然可以通过在表面覆盖大量的小三角形来得到一个近似的球体,但这会增加更多的图形绘制成本。

用于表现几何形状的替代方法是存在的。其中一个就是使用有向距离函数,即要展现物体的数学描述。当用一个球体方程来取代它的几何形状时,就能把所有由近似描述所带来的错误从3D引擎中移除。你可以将有向距离函数视作与SVG等量的三角形。可以缩放和变焦SDF的几何形状而不丢失细节。无论离边缘有多近,球体永远都是光滑的。

有向距离函数基于这样一种思想,即每个原始对象都必须有一个对应的函数。它以3D坐标作为参数,并返回一个值,用于表示这个点与物体表面的距离。

SDF 球体
 

系列第一篇立体渲染中,有一个用于计算点是否在球体内的函数:

泰课在线

 

可以改变这个函数让它返回距离球体表面的距离:

泰课在线

如果sdf_spher 返回了一个正数,那就表示没有碰撞到球体。返回负数则表示点是在球体内,而零表示球体表面上的点。

并集和交集
 

上一篇Raymarching教程中, 在介绍摄像机射线到材质的进阶部分中, 我们简要介绍了有向距离函数的概念。另一个使用有向距离函数的原因,是它们是适合进行组合的。比如有两个不同球形的SDFs,应该如何将它们合并成一个呢?

我们可以从相机射线的角度来考虑这个问题。在每一步中,射线必须找到与它最接近的障碍物。如果有两个球体,我们需要评估两者的距离以得到最小值,因为不希望射线超出球体的范围太多,所以必须作最保守的估算。
这个例子可以扩展到任何两个SDF,获取它们之间的最小值并返回相当于二者并集的SDF:

泰课在线

结果如下(它还具有其它视觉增强功能):

泰课在线

同理,获取两个SDF的最大值则返回了它们的交集:

泰课在线

泰课在线

 

SDF 盒子
 

很多几何图形可以用已知的方式进行构建。如果想更深入,就需要引入新的SDF原型:半空间。正如其名字的字面意思,它只是一个原始的占据了半个3D空间的东西。

泰课在线

关键点是要用6个平面相交,以创建一个给定大小为s的盒子,就如下面动画所示:

泰课在线

泰课在线

有更简洁(但不够精确)的方法来创建盒子,利用了中心周围的对称性:

泰课在线

 

形状混合
 

如果熟悉alpha混合的概念,应该很了解下面的代码:

泰课在线

其目的是创建d1和d2两个值之间的混合,通过a的值(从0到1)进行控制。用于混合颜色的代码也可以用于混合形状。例如,下面的代码将一个球体混合到一个立方体中:

泰课在线

泰课在线

 

光滑合并
 

在上一节中已经看到两个SDF可以通过取最小值的方式合并在一起。SDF的合集虽然确实是有效的,但它的结果会有一点不真实。SDF可以将原物体以多种方式混合在一起。其中一个技巧就是指数平滑,已被广泛用于实现本教程最上方的动画效果。

 

泰课在线

 
当两个形状以这个新的操作进行结合时,它们会平滑地合并,以轻柔的步骤移除所有锋利的边缘。在下面的动画中,可以看到球体是如何合并在一起的:

泰课在线

SDF 代数
 

可以预见的是,那些SDF元物体以及操作是有向距离函数代数的一部分。旋转,缩放,混合,扭曲…所有这些操作都可以用有向距离函数来表示。

结论

可以通过SDF表现的几何体几乎是无限的,这篇文章只是提供该主题的简介。如果想掌握立体渲染,加深对SDF的了解是一个很好的起点。