8

我一直在查看并试图理解以下代码

float sdBox( vec3 p, vec3 b )
{
  vec3 d = abs(p) - b;
  return min(max(d.x,max(d.y,d.z)),0.0) +
         length(max(d,0.0));
}

我知道length(d)处理 SDF 情况,其中点偏离“角落”(即所有组件d都是正的),并且max(d.x, d.y, d.z)在所有其他情况下为我们提供了适当的距离。我不明白的是如何在不使用 if 语句检查d's 组件的符号的情况下将这两者结合在这里。

当所有d分量都为正时,返回表达式可以简化为,length(d)因为min/max评估方式 - 当所有d分量都为负时,我们得到max(d.x, d.y, d.z). 但是我应该如何理解中间情况呢?的成分d有混合迹象的那些?

我一直试图绘制它无济于事。如果有人能用几何/数学术语向我解释这一点,我将不胜感激。谢谢。

4

2 回答 2

10
于 2018-04-09T06:22:05.950 回答
4

我不久前想通了,并在这里的一篇博文中广泛地写了这篇文章:http: //fabricecastel.github.io/blog/2016-02-11/main.html

这是一段摘录(有关完整说明,请参阅完整帖子):

考虑 A、B、C 和 D 这四个点。让我们粗略地减少距离函数以尝试摆脱最小/最大函数以了解它们的效果(因为这就是这个函数令人费解的地方)。下面的符号有点草率,我使用方括号来表示二维向量。

// 2D version of the function
d(p) = min(max(p.x, p.y), 0)
       + length(max(p, 0))

---

d(A) = min(max(-1, -1), 0)
       + length(max([-1, -1], 0))

d(A) = -1 + length[0, 0]

---

d(B) = min(max(1, 1), 0)
       + length(max([1, 1], 0))

d(B) = 0 + length[1, 1]

好的,到目前为止没有什么特别的。当 A 在正方形内时,我们基本上得到了基于平面/线的第一个距离函数,而当 B 在我们的第一个距离函数不准确的区域中时,它被归零,我们得到第二个距离函数(长度)。诀窍在于其他两种情况 C 和 D。让我们解决它们。

d(C) = min(max(-1, 1), 0)
      + length(max([-1, 1], 0))

d(C) = 0 + length[0, 1]

---

d(D) = min(max(1, -1), 0)
       + length(max([-1, 1], 0))

d(D) = 0 + length[1, 0]

如果您回头看上面的图表,您会注意到 C' 和 D'。这些点的坐标分别为 [0,1] 和 [1,0]。该方法利用了两个距离场在轴上相交的事实 - D 和 D' 与正方形的距离相同。

如果我们将向量的所有负分量归零并取其长度,我们将得到点和正方形之间的适当距离(仅适用于正方形之外的点)。这就是 max(d,0.0) 的作用;一个组件方式的最大操作。只要向量至少有一个正分量,min(max(dx,dy),0.0) 就会解析为 0,只剩下等式的第二部分。如果该点在正方形内,我们希望返回方程的第一部分(因为它代表我们的第一个距离函数)。如果向量的所有分量都是负数,很容易看出我们的条件会得到满足。

一旦你把头绕在它周围,这种理解应该无缝地转换回 3D。您可能需要也可能不需要手动绘制一些图表才能真正“得到”它——我知道我做过,如果你对我的解释不满意,我会鼓励你这样做。

将此实现应用到我们自己的代码中,我们得到:

float distanceToNearestSurface(vec3 p){
  float s = 1.0;
  vec3 d = abs(p) - vec3(s);
  return min(max(d.x, max(d.y,d.z)), 0.0)
      + length(max(d,0.0));
}

你有它。

于 2017-01-29T01:45:27.897 回答