Unity立体渲染 有向距离函数
本篇将介绍如何在体积着色器中创建复杂的三维模型。
有向距离函数(通常被称为场)是一种用于描述球形、盒子及环面等几何形状的数学工具。与传统的由三角形组成的3D模型相比,有向距离函数具有几乎无限的分辨率,并且非常适合进行几何体操作。下面的动画展示了如何使用更简单的形状来创建一个蜗牛。
介绍
大多数现代的3D引擎(如Unity)采用三角形来处理几何体。无论物体多么复杂,都是由原始的三角形组合而成。尽管这在计算机图形学中是实际标准,但并非所有物体都能用三角形精确表示。例如,球形以及其他曲面几何形状无法细分为平面实体。虽然可以通过在表面覆盖大量的小三角形来近似表示一个球体,但这会显著增加图形绘制成本。
实际上,存在用于表现几何形状的替代方法,其中之一就是使用有向距离函数,即对要展现物体的数学描述。当用一个球体方程来取代它的几何形状时,就能消除3D引擎中所有由近似描述带来的误差。可以将有向距离函数视作与SVG等价的三角形表示方式。可以对有向距离函数(SDF)所描述的几何形状进行缩放和变焦操作,而不会丢失细节。无论离边缘多近,球体始终保持光滑。
有向距离函数基于这样的思想:每个原始对象都有一个对应的函数,该函数以3D坐标作为参数,并返回一个值,表示该点与物体表面的距离。
SDF 球体
在系列第一篇立体渲染中,有一个用于计算点是否在球体内的函数。我们可以对这个函数进行修改,使其返回该点到球体表面的距离。
如果 sdf_spher 返回一个正数,则表示该点没有与球体发生碰撞;返回负数表示该点在球体内;返回零则表示该点位于球体表面。
并集和交集
在上一篇Raymarching教程的摄像机射线到材质的进阶部分中,我们简要介绍了有向距离函数的概念。使用有向距离函数的另一个原因是,它们非常适合进行组合操作。例如,假设有两个不同球形的SDF,应该如何将它们合并成一个呢?
我们可以从相机射线的角度来思考这个问题。在每一步中,射线需要找到与其最接近的障碍物。如果有两个球体,我们需要评估两者的距离并取最小值,因为我们不希望射线超出球体范围太多,所以必须进行最保守的估算。
这个例子可以扩展到任意两个SDF,通过获取它们之间的最小值并返回,相当于得到了二者的并集SDF。结果如下(它还具有其他视觉增强功能)。
同理,获取两个SDF的最大值则返回了它们的交集。
SDF 盒子
许多几何图形可以通过已知的方式进行构建。如果想更深入地研究,就需要引入新的SDF原型:半空间。正如其名称所示,它是一个占据半个3D空间的基本元素。
关键点是使用6个平面相交,以创建一个给定大小为 s 的盒子,如下面的动画所示。
此外,还有一种更简洁(但不够精确)的方法来创建盒子,利用了中心周围的对称性。
形状混合
如果熟悉alpha混合的概念,应该对下面的代码很熟悉。其目的是创建 d1 和 d2 两个值之间的混合,通过 a 的值(范围从0到1)进行控制。用于混合颜色的代码同样可以用于混合形状。例如,下面的代码将一个球体混合到一个立方体中。
光滑合并
在上一节中,我们看到可以通过取最小值的方式将两个SDF合并在一起。虽然SDF的合集是有效的,但结果可能会显得有些不真实。SDF可以通过多种方式将原物体混合在一起,其中一种技巧是指数平滑,该方法已被广泛用于实现本教程最上方的动画效果。
当两个形状通过这种新的操作进行结合时,它们会平滑地合并,以轻柔的步骤消除所有锋利的边缘。在下面的动画中,可以看到球体是如何平滑合并在一起的。
SDF 代数
可以预见的是,那些SDF元物体以及相关操作是有向距离函数代数的一部分。旋转、缩放、混合、扭曲等所有这些操作都可以用有向距离函数来表示。
结论
可以通过SDF表现的几何体几乎是无限的,本文只是对该主题进行了简要介绍。如果想掌握立体渲染,深入了解SDF是一个很好的起点。